mirror of
				https://github.com/DigitalDevices/pvr.octonet.git
				synced 2025-03-01 10:53:09 +00:00 
			
		
		
		
	clang code cleanup
This commit is contained in:
		
							
								
								
									
										88
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
---
 | 
			
		||||
# BasedOnStyle:  LLVM
 | 
			
		||||
AccessModifierOffset: -2
 | 
			
		||||
AlignAfterOpenBracket: Align
 | 
			
		||||
AlignConsecutiveAssignments: false
 | 
			
		||||
AlignConsecutiveDeclarations: false
 | 
			
		||||
AlignEscapedNewlines: DontAlign
 | 
			
		||||
AlignOperands:   true
 | 
			
		||||
AlignTrailingComments: false
 | 
			
		||||
AllowAllParametersOfDeclarationOnNextLine: true
 | 
			
		||||
AllowShortBlocksOnASingleLine: false
 | 
			
		||||
AllowShortCaseLabelsOnASingleLine: false
 | 
			
		||||
AllowShortFunctionsOnASingleLine: InlineOnly
 | 
			
		||||
AllowShortIfStatementsOnASingleLine: false
 | 
			
		||||
AllowShortLoopsOnASingleLine: false
 | 
			
		||||
AlwaysBreakAfterDefinitionReturnType: None
 | 
			
		||||
AlwaysBreakAfterReturnType: None
 | 
			
		||||
AlwaysBreakBeforeMultilineStrings: false
 | 
			
		||||
AlwaysBreakTemplateDeclarations: true
 | 
			
		||||
BinPackArguments: true
 | 
			
		||||
BinPackParameters: false
 | 
			
		||||
BreakBeforeBinaryOperators: None
 | 
			
		||||
BreakBeforeBraces: Allman
 | 
			
		||||
BreakBeforeTernaryOperators: true
 | 
			
		||||
BreakConstructorInitializersBeforeComma: false
 | 
			
		||||
BreakConstructorInitializers: BeforeColon
 | 
			
		||||
BreakAfterJavaFieldAnnotations: false
 | 
			
		||||
BreakStringLiterals: true
 | 
			
		||||
ColumnLimit:     100
 | 
			
		||||
CommentPragmas:  '^ IWYU pragma:'
 | 
			
		||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
 | 
			
		||||
ConstructorInitializerIndentWidth: 2
 | 
			
		||||
ContinuationIndentWidth: 4
 | 
			
		||||
Cpp11BracedListStyle: true
 | 
			
		||||
DerivePointerAlignment: false
 | 
			
		||||
DisableFormat:   false
 | 
			
		||||
ExperimentalAutoDetectBinPacking: false
 | 
			
		||||
ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
 | 
			
		||||
IncludeBlocks: Regroup
 | 
			
		||||
IncludeCategories:
 | 
			
		||||
  - Regex:           '^<[a-z0-9_]+>$'
 | 
			
		||||
    Priority:        3
 | 
			
		||||
  - Regex:           '^<(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdarg|stdatomic|stdbool|stddef|stdint|stdio|stdlib|stdnoreturn|string|tgmath|threads|time|uchar|wchar|wctype)\.h>$'
 | 
			
		||||
    Priority:        3
 | 
			
		||||
  - Regex:           '^<'
 | 
			
		||||
    Priority:        3
 | 
			
		||||
  - Regex:           '^["<](kodi|p8-platform)\/.*\.h[">]$'
 | 
			
		||||
    Priority:        2
 | 
			
		||||
  - Regex:           '.*'
 | 
			
		||||
    Priority:        1
 | 
			
		||||
IncludeIsMainRegex: '$'
 | 
			
		||||
IndentCaseLabels: true
 | 
			
		||||
IndentWidth:     2
 | 
			
		||||
IndentWrappedFunctionNames: false
 | 
			
		||||
JavaScriptQuotes: Leave
 | 
			
		||||
JavaScriptWrapImports: true
 | 
			
		||||
KeepEmptyLinesAtTheStartOfBlocks: true
 | 
			
		||||
MacroBlockBegin: ''
 | 
			
		||||
MacroBlockEnd:   ''
 | 
			
		||||
MaxEmptyLinesToKeep: 2
 | 
			
		||||
NamespaceIndentation: None
 | 
			
		||||
ObjCBlockIndentWidth: 2
 | 
			
		||||
ObjCSpaceAfterProperty: false
 | 
			
		||||
ObjCSpaceBeforeProtocolList: true
 | 
			
		||||
PenaltyBreakBeforeFirstCallParameter: 19
 | 
			
		||||
PenaltyBreakComment: 300
 | 
			
		||||
PenaltyBreakFirstLessLess: 120
 | 
			
		||||
PenaltyBreakString: 1000
 | 
			
		||||
PenaltyExcessCharacter: 1000000
 | 
			
		||||
PenaltyReturnTypeOnItsOwnLine: 60000
 | 
			
		||||
PointerAlignment: Left
 | 
			
		||||
ReflowComments:  false
 | 
			
		||||
SortIncludes:    true
 | 
			
		||||
SpaceAfterCStyleCast: false
 | 
			
		||||
SpaceAfterTemplateKeyword: false
 | 
			
		||||
SpaceBeforeAssignmentOperators: true
 | 
			
		||||
SpaceBeforeParens: ControlStatements
 | 
			
		||||
SpaceInEmptyParentheses: false
 | 
			
		||||
SpacesBeforeTrailingComments: 1
 | 
			
		||||
SpacesInAngles:  false
 | 
			
		||||
SpacesInContainerLiterals: true
 | 
			
		||||
SpacesInCStyleCastParentheses: false
 | 
			
		||||
SpacesInParentheses: false
 | 
			
		||||
SpacesInSquareBrackets: false
 | 
			
		||||
Standard:        Cpp11
 | 
			
		||||
TabWidth:        8
 | 
			
		||||
UseTab:          Never
 | 
			
		||||
...
 | 
			
		||||
@@ -8,12 +8,11 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "OctonetData.h"
 | 
			
		||||
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
 | 
			
		||||
#include "OctonetData.h"
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#ifdef __WINDOWS__
 | 
			
		||||
#define timegm _mkgmtime
 | 
			
		||||
@@ -23,22 +22,22 @@ using namespace ADDON;
 | 
			
		||||
 | 
			
		||||
OctonetData::OctonetData()
 | 
			
		||||
{
 | 
			
		||||
	serverAddress = octonetAddress;
 | 
			
		||||
	channels.clear();
 | 
			
		||||
	groups.clear();
 | 
			
		||||
	lastEpgLoad = 0;
 | 
			
		||||
  m_serverAddress = octonetAddress;
 | 
			
		||||
  m_channels.clear();
 | 
			
		||||
  m_groups.clear();
 | 
			
		||||
  m_lastEpgLoad = 0;
 | 
			
		||||
 | 
			
		||||
	if (!loadChannelList())
 | 
			
		||||
		libKodi->QueueNotification(QUEUE_ERROR, libKodi->GetLocalizedString(30001), channels.size());
 | 
			
		||||
  if (!LoadChannelList())
 | 
			
		||||
    libKodi->QueueNotification(QUEUE_ERROR, libKodi->GetLocalizedString(30001), m_channels.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OctonetData::~OctonetData(void)
 | 
			
		||||
{
 | 
			
		||||
	channels.clear();
 | 
			
		||||
	groups.clear();
 | 
			
		||||
  m_channels.clear();
 | 
			
		||||
  m_groups.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t OctonetData::parseID(std::string id)
 | 
			
		||||
int64_t OctonetData::ParseID(std::string id)
 | 
			
		||||
{
 | 
			
		||||
  std::hash<std::string> hash_fn;
 | 
			
		||||
  int64_t nativeId = hash_fn(id);
 | 
			
		||||
@@ -46,10 +45,11 @@ int64_t OctonetData::parseID(std::string id)
 | 
			
		||||
  return nativeId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OctonetData::loadChannelList()
 | 
			
		||||
bool OctonetData::LoadChannelList()
 | 
			
		||||
{
 | 
			
		||||
  std::string jsonContent;
 | 
			
		||||
	void *f = libKodi->OpenFile(("http://" + serverAddress + "/channellist.lua?select=json").c_str(), 0);
 | 
			
		||||
  void* f =
 | 
			
		||||
      libKodi->OpenFile(("http://" + m_serverAddress + "/channellist.lua?select=json").c_str(), 0);
 | 
			
		||||
  if (!f)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
@@ -66,36 +66,39 @@ bool OctonetData::loadChannelList()
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  const Json::Value groupList = root["GroupList"];
 | 
			
		||||
	for (unsigned int i = 0; i < groupList.size(); i++) {
 | 
			
		||||
  for (unsigned int i = 0; i < groupList.size(); i++)
 | 
			
		||||
  {
 | 
			
		||||
    const Json::Value channelList = groupList[i]["ChannelList"];
 | 
			
		||||
    OctonetGroup group;
 | 
			
		||||
 | 
			
		||||
    group.name = groupList[i]["Title"].asString();
 | 
			
		||||
    group.radio = group.name.compare(0, 5, "Radio") ? false : true;
 | 
			
		||||
 | 
			
		||||
		for (unsigned int j = 0; j < channelList.size(); j++) {
 | 
			
		||||
    for (unsigned int j = 0; j < channelList.size(); j++)
 | 
			
		||||
    {
 | 
			
		||||
      const Json::Value channel = channelList[j];
 | 
			
		||||
      OctonetChannel chan;
 | 
			
		||||
 | 
			
		||||
      chan.name = channel["Title"].asString();
 | 
			
		||||
			chan.url = "rtsp://" + serverAddress + "/" + channel["Request"].asString();
 | 
			
		||||
      chan.url = "rtsp://" + m_serverAddress + "/" + channel["Request"].asString();
 | 
			
		||||
      chan.radio = group.radio;
 | 
			
		||||
			chan.nativeId = parseID(channel["ID"].asString());
 | 
			
		||||
      chan.nativeId = ParseID(channel["ID"].asString());
 | 
			
		||||
 | 
			
		||||
			chan.id = 1000 + channels.size();
 | 
			
		||||
			group.members.push_back(channels.size());
 | 
			
		||||
			channels.push_back(chan);
 | 
			
		||||
      chan.id = 1000 + m_channels.size();
 | 
			
		||||
      group.members.push_back(m_channels.size());
 | 
			
		||||
      m_channels.push_back(chan);
 | 
			
		||||
    }
 | 
			
		||||
		groups.push_back(group);
 | 
			
		||||
    m_groups.push_back(group);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OctonetChannel* OctonetData::findChannel(int64_t nativeId)
 | 
			
		||||
OctonetChannel* OctonetData::FindChannel(int64_t nativeId)
 | 
			
		||||
{
 | 
			
		||||
  std::vector<OctonetChannel>::iterator it;
 | 
			
		||||
	for (it = channels.begin(); it < channels.end(); ++it) {
 | 
			
		||||
  for (it = m_channels.begin(); it < m_channels.end(); ++it)
 | 
			
		||||
  {
 | 
			
		||||
    if (it->nativeId == nativeId)
 | 
			
		||||
      return &*it;
 | 
			
		||||
  }
 | 
			
		||||
@@ -103,21 +106,22 @@ OctonetChannel* OctonetData::findChannel(int64_t nativeId)
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
time_t OctonetData::parseDateTime(std::string date)
 | 
			
		||||
time_t OctonetData::ParseDateTime(std::string date)
 | 
			
		||||
{
 | 
			
		||||
  struct tm timeinfo;
 | 
			
		||||
 | 
			
		||||
  memset(&timeinfo, 0, sizeof(timeinfo));
 | 
			
		||||
 | 
			
		||||
	if (date.length() > 8) {
 | 
			
		||||
		sscanf(date.c_str(), "%04d-%02d-%02dT%02d:%02d:%02dZ",
 | 
			
		||||
				&timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday,
 | 
			
		||||
				&timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
			
		||||
  if (date.length() > 8)
 | 
			
		||||
  {
 | 
			
		||||
    sscanf(date.c_str(), "%04d-%02d-%02dT%02d:%02d:%02dZ", &timeinfo.tm_year, &timeinfo.tm_mon,
 | 
			
		||||
           &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
			
		||||
    timeinfo.tm_mon -= 1;
 | 
			
		||||
    timeinfo.tm_year -= 1900;
 | 
			
		||||
	} else {
 | 
			
		||||
		sscanf(date.c_str(), "%02d:%02d:%02d",
 | 
			
		||||
				&timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    sscanf(date.c_str(), "%02d:%02d:%02d", &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec);
 | 
			
		||||
    timeinfo.tm_year = 70; // unix timestamps start 1970
 | 
			
		||||
    timeinfo.tm_mday = 1;
 | 
			
		||||
  }
 | 
			
		||||
@@ -127,14 +131,14 @@ time_t OctonetData::parseDateTime(std::string date)
 | 
			
		||||
  return timegm(&timeinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OctonetData::loadEPG(void)
 | 
			
		||||
bool OctonetData::LoadEPG(void)
 | 
			
		||||
{
 | 
			
		||||
  /* Reload at most every 30 seconds */
 | 
			
		||||
	if (lastEpgLoad + 30 > time(NULL))
 | 
			
		||||
  if (m_lastEpgLoad + 30 > time(NULL))
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  std::string jsonContent;
 | 
			
		||||
	void *f = libKodi->OpenFile(("http://" + serverAddress + "/epg.lua?;#|encoding=gzip").c_str(), 0);
 | 
			
		||||
  void* f = libKodi->OpenFile(("http://" + m_serverAddress + "/epg.lua?;#|encoding=gzip").c_str(), 0);
 | 
			
		||||
  if (!f)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
@@ -151,26 +155,28 @@ bool OctonetData::loadEPG(void)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  const Json::Value eventList = root["EventList"];
 | 
			
		||||
	OctonetChannel *channel = NULL;
 | 
			
		||||
	for (unsigned int i = 0; i < eventList.size(); i++) {
 | 
			
		||||
  OctonetChannel* channel = NULL;
 | 
			
		||||
  for (unsigned int i = 0; i < eventList.size(); i++)
 | 
			
		||||
  {
 | 
			
		||||
    const Json::Value event = eventList[i];
 | 
			
		||||
    OctonetEpgEntry entry;
 | 
			
		||||
 | 
			
		||||
		entry.start = parseDateTime(event["Time"].asString());
 | 
			
		||||
		entry.end = entry.start + parseDateTime(event["Duration"].asString());
 | 
			
		||||
    entry.start = ParseDateTime(event["Time"].asString());
 | 
			
		||||
    entry.end = entry.start + ParseDateTime(event["Duration"].asString());
 | 
			
		||||
    entry.title = event["Name"].asString();
 | 
			
		||||
    entry.subtitle = event["Text"].asString();
 | 
			
		||||
    std::string channelId = event["ID"].asString();
 | 
			
		||||
    std::string epgId = channelId.substr(channelId.rfind(":") + 1);
 | 
			
		||||
    channelId = channelId.substr(0, channelId.rfind(":"));
 | 
			
		||||
 | 
			
		||||
		entry.channelId = parseID(channelId);
 | 
			
		||||
    entry.channelId = ParseID(channelId);
 | 
			
		||||
    entry.id = atoi(epgId.c_str());
 | 
			
		||||
 | 
			
		||||
    if (channel == NULL || channel->nativeId != entry.channelId)
 | 
			
		||||
			channel = findChannel(entry.channelId);
 | 
			
		||||
      channel = FindChannel(entry.channelId);
 | 
			
		||||
 | 
			
		||||
		if (channel == NULL) {
 | 
			
		||||
    if (channel == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      libKodi->Log(LOG_ERROR, "EPG for unknown channel.");
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
@@ -178,25 +184,25 @@ bool OctonetData::loadEPG(void)
 | 
			
		||||
    channel->epg.push_back(entry);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
	lastEpgLoad = time(NULL);
 | 
			
		||||
  m_lastEpgLoad = time(NULL);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *OctonetData::Process(void)
 | 
			
		||||
void* OctonetData::Process(void)
 | 
			
		||||
{
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int OctonetData::getChannelCount(void)
 | 
			
		||||
{
 | 
			
		||||
	return channels.size();
 | 
			
		||||
  return m_channels.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PVR_ERROR OctonetData::getChannels(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned int i = 0; i < channels.size(); i++)
 | 
			
		||||
  for (unsigned int i = 0; i < m_channels.size(); i++)
 | 
			
		||||
  {
 | 
			
		||||
		OctonetChannel &channel = channels.at(i);
 | 
			
		||||
    OctonetChannel& channel = m_channels.at(i);
 | 
			
		||||
    if (channel.radio == bRadio)
 | 
			
		||||
    {
 | 
			
		||||
      PVR_CHANNEL chan;
 | 
			
		||||
@@ -217,25 +223,28 @@ PVR_ERROR OctonetData::getChannels(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
 | 
			
		||||
PVR_ERROR OctonetData::getEPG(ADDON_HANDLE handle, int iChannelUid, time_t start, time_t end)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned int i = 0; i < channels.size(); i++)
 | 
			
		||||
  for (unsigned int i = 0; i < m_channels.size(); i++)
 | 
			
		||||
  {
 | 
			
		||||
		OctonetChannel &chan = channels.at(i);
 | 
			
		||||
    OctonetChannel& chan = m_channels.at(i);
 | 
			
		||||
    if (iChannelUid != chan.id)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
		if(chan.epg.empty()) {
 | 
			
		||||
			loadEPG();
 | 
			
		||||
    if (chan.epg.empty())
 | 
			
		||||
    {
 | 
			
		||||
      LoadEPG();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // FIXME: Check if reload is needed!?
 | 
			
		||||
 | 
			
		||||
    std::vector<OctonetEpgEntry>::iterator it;
 | 
			
		||||
    time_t last_end = 0;
 | 
			
		||||
		for (it = chan.epg.begin(); it != chan.epg.end(); ++it) {
 | 
			
		||||
    for (it = chan.epg.begin(); it != chan.epg.end(); ++it)
 | 
			
		||||
    {
 | 
			
		||||
      if (it->end > last_end)
 | 
			
		||||
        last_end = it->end;
 | 
			
		||||
 | 
			
		||||
			if (it->end < start || it->start > end) {
 | 
			
		||||
      if (it->end < start || it->start > end)
 | 
			
		||||
      {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -256,10 +265,12 @@ PVR_ERROR OctonetData::getEPG(ADDON_HANDLE handle, int iChannelUid, time_t start
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (last_end < end)
 | 
			
		||||
			loadEPG();
 | 
			
		||||
      LoadEPG();
 | 
			
		||||
 | 
			
		||||
		for (it = chan.epg.begin(); it != chan.epg.end(); ++it) {
 | 
			
		||||
			if (it->end < start || it->start > end) {
 | 
			
		||||
    for (it = chan.epg.begin(); it != chan.epg.end(); ++it)
 | 
			
		||||
    {
 | 
			
		||||
      if (it->end < start || it->start > end)
 | 
			
		||||
      {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -283,36 +294,44 @@ PVR_ERROR OctonetData::getEPG(ADDON_HANDLE handle, int iChannelUid, time_t start
 | 
			
		||||
  return PVR_ERROR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::string& OctonetData::getUrl(int id) const {
 | 
			
		||||
	for(std::vector<OctonetChannel>::const_iterator iter = channels.begin(); iter != channels.end(); ++iter) {
 | 
			
		||||
		if(iter->id == id) {
 | 
			
		||||
const std::string& OctonetData::GetUrl(int id) const
 | 
			
		||||
{
 | 
			
		||||
  for (std::vector<OctonetChannel>::const_iterator iter = m_channels.begin(); iter != m_channels.end();
 | 
			
		||||
       ++iter)
 | 
			
		||||
  {
 | 
			
		||||
    if (iter->id == id)
 | 
			
		||||
    {
 | 
			
		||||
      return iter->url;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
	return channels[0].url;
 | 
			
		||||
  return m_channels[0].url;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::string& OctonetData::getName(int id) const {
 | 
			
		||||
	for(std::vector<OctonetChannel>::const_iterator iter = channels.begin(); iter != channels.end(); ++iter) {
 | 
			
		||||
		if(iter->id == id) {
 | 
			
		||||
const std::string& OctonetData::GetName(int id) const
 | 
			
		||||
{
 | 
			
		||||
  for (std::vector<OctonetChannel>::const_iterator iter = m_channels.begin(); iter != m_channels.end();
 | 
			
		||||
       ++iter)
 | 
			
		||||
  {
 | 
			
		||||
    if (iter->id == id)
 | 
			
		||||
    {
 | 
			
		||||
      return iter->name;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
	return channels[0].name;
 | 
			
		||||
  return m_channels[0].name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int OctonetData::getGroupCount(void)
 | 
			
		||||
{
 | 
			
		||||
	return groups.size();
 | 
			
		||||
  return m_groups.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PVR_ERROR OctonetData::getGroups(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned int i = 0; i < groups.size(); i++)
 | 
			
		||||
  for (unsigned int i = 0; i < m_groups.size(); i++)
 | 
			
		||||
  {
 | 
			
		||||
		OctonetGroup &group = groups.at(i);
 | 
			
		||||
    OctonetGroup& group = m_groups.at(i);
 | 
			
		||||
    if (group.radio == bRadio)
 | 
			
		||||
    {
 | 
			
		||||
      PVR_CHANNEL_GROUP g;
 | 
			
		||||
@@ -329,15 +348,15 @@ PVR_ERROR OctonetData::getGroups(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
  return PVR_ERROR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PVR_ERROR OctonetData::getGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group)
 | 
			
		||||
PVR_ERROR OctonetData::getGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group)
 | 
			
		||||
{
 | 
			
		||||
	OctonetGroup *g = findGroup(group.strGroupName);
 | 
			
		||||
  OctonetGroup* g = FindGroup(group.strGroupName);
 | 
			
		||||
  if (g == NULL)
 | 
			
		||||
    return PVR_ERROR_UNKNOWN;
 | 
			
		||||
 | 
			
		||||
  for (unsigned int i = 0; i < g->members.size(); i++)
 | 
			
		||||
  {
 | 
			
		||||
		OctonetChannel &channel = channels.at(g->members[i]);
 | 
			
		||||
    OctonetChannel& channel = m_channels.at(g->members[i]);
 | 
			
		||||
    PVR_CHANNEL_GROUP_MEMBER m;
 | 
			
		||||
    memset(&m, 0, sizeof(PVR_CHANNEL_GROUP_MEMBER));
 | 
			
		||||
 | 
			
		||||
@@ -351,12 +370,12 @@ PVR_ERROR OctonetData::getGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GR
 | 
			
		||||
  return PVR_ERROR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OctonetGroup* OctonetData::findGroup(const std::string &name)
 | 
			
		||||
OctonetGroup* OctonetData::FindGroup(const std::string& name)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned int i = 0; i < groups.size(); i++)
 | 
			
		||||
  for (unsigned int i = 0; i < m_groups.size(); i++)
 | 
			
		||||
  {
 | 
			
		||||
		if (groups.at(i).name == name)
 | 
			
		||||
			return &groups.at(i);
 | 
			
		||||
    if (m_groups.at(i).name == name)
 | 
			
		||||
      return &m_groups.at(i);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,10 +10,11 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "client.h"
 | 
			
		||||
 | 
			
		||||
#include "p8-platform/threads/threads.h"
 | 
			
		||||
#include "client.h"
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
struct OctonetEpgEntry
 | 
			
		||||
{
 | 
			
		||||
@@ -45,7 +46,7 @@ struct OctonetGroup
 | 
			
		||||
 | 
			
		||||
class OctonetData : public P8PLATFORM::CThread
 | 
			
		||||
{
 | 
			
		||||
	public:
 | 
			
		||||
public:
 | 
			
		||||
  OctonetData(void);
 | 
			
		||||
  virtual ~OctonetData(void);
 | 
			
		||||
 | 
			
		||||
@@ -54,27 +55,26 @@ class OctonetData : public P8PLATFORM::CThread
 | 
			
		||||
 | 
			
		||||
  virtual int getGroupCount(void);
 | 
			
		||||
  virtual PVR_ERROR getGroups(ADDON_HANDLE handle, bool bRadio);
 | 
			
		||||
		virtual PVR_ERROR getGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group);
 | 
			
		||||
  virtual PVR_ERROR getGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group);
 | 
			
		||||
 | 
			
		||||
  virtual PVR_ERROR getEPG(ADDON_HANDLE handle, int iChannelUid, time_t start, time_t end);
 | 
			
		||||
		const std::string& getUrl(int id) const;
 | 
			
		||||
		const std::string& getName(int id) const;
 | 
			
		||||
  const std::string& GetUrl(int id) const;
 | 
			
		||||
  const std::string& GetName(int id) const;
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		virtual bool loadChannelList(void);
 | 
			
		||||
		virtual bool loadEPG(void);
 | 
			
		||||
		virtual OctonetGroup* findGroup(const std::string &name);
 | 
			
		||||
protected:
 | 
			
		||||
  void* Process(void) override;
 | 
			
		||||
 | 
			
		||||
		virtual void *Process(void);
 | 
			
		||||
  bool LoadChannelList(void);
 | 
			
		||||
  bool LoadEPG(void);
 | 
			
		||||
  OctonetGroup* FindGroup(const std::string& name);
 | 
			
		||||
  OctonetChannel* FindChannel(int64_t nativeId);
 | 
			
		||||
  time_t ParseDateTime(std::string date);
 | 
			
		||||
  int64_t ParseID(std::string id);
 | 
			
		||||
 | 
			
		||||
		OctonetChannel* findChannel(int64_t nativeId);
 | 
			
		||||
		time_t parseDateTime(std::string date);
 | 
			
		||||
		int64_t parseID(std::string id);
 | 
			
		||||
private:
 | 
			
		||||
  std::string m_serverAddress;
 | 
			
		||||
  std::vector<OctonetChannel> m_channels;
 | 
			
		||||
  std::vector<OctonetGroup> m_groups;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		std::string serverAddress;
 | 
			
		||||
		std::vector<OctonetChannel> channels;
 | 
			
		||||
		std::vector<OctonetGroup> groups;
 | 
			
		||||
 | 
			
		||||
		time_t lastEpgLoad;
 | 
			
		||||
  time_t m_lastEpgLoad;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										258
									
								
								src/Socket.cpp
									
									
									
									
									
								
							
							
						
						
									
										258
									
								
								src/Socket.cpp
									
									
									
									
									
								
							@@ -6,12 +6,15 @@
 | 
			
		||||
 *  See LICENSE.md for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "kodi/libXBMC_addon.h"
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "p8-platform/os.h"
 | 
			
		||||
#include "client.h"
 | 
			
		||||
#include "Socket.h"
 | 
			
		||||
 | 
			
		||||
#include "client.h"
 | 
			
		||||
 | 
			
		||||
#include "kodi/libXBMC_addon.h"
 | 
			
		||||
#include "p8-platform/os.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
using namespace ADDON;
 | 
			
		||||
@@ -22,28 +25,31 @@ namespace OCTO
 | 
			
		||||
/* Master defines for client control */
 | 
			
		||||
#define RECEIVE_TIMEOUT 6 //sec
 | 
			
		||||
 | 
			
		||||
Socket::Socket(const enum SocketFamily family, const enum SocketDomain domain, const enum SocketType type, const enum SocketProtocol protocol)
 | 
			
		||||
Socket::Socket(const enum SocketFamily family,
 | 
			
		||||
               const enum SocketDomain domain,
 | 
			
		||||
               const enum SocketType type,
 | 
			
		||||
               const enum SocketProtocol protocol)
 | 
			
		||||
{
 | 
			
		||||
  _sd = INVALID_SOCKET;
 | 
			
		||||
  _family = family;
 | 
			
		||||
  _domain = domain;
 | 
			
		||||
  _type = type;
 | 
			
		||||
  _protocol = protocol;
 | 
			
		||||
  _port = 0;
 | 
			
		||||
  memset (&_sockaddr, 0, sizeof( _sockaddr ) );
 | 
			
		||||
  m_sd = INVALID_SOCKET;
 | 
			
		||||
  m_family = family;
 | 
			
		||||
  m_domain = domain;
 | 
			
		||||
  m_type = type;
 | 
			
		||||
  m_protocol = protocol;
 | 
			
		||||
  m_port = 0;
 | 
			
		||||
  memset(&m_sockaddr, 0, sizeof(m_sockaddr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Socket::Socket()
 | 
			
		||||
{
 | 
			
		||||
  // Default constructor, default settings
 | 
			
		||||
  _sd = INVALID_SOCKET;
 | 
			
		||||
  _family = af_inet;
 | 
			
		||||
  _domain = pf_inet;
 | 
			
		||||
  _type = sock_stream;
 | 
			
		||||
  _protocol = tcp;
 | 
			
		||||
  _port = 0;
 | 
			
		||||
  memset (&_sockaddr, 0, sizeof( _sockaddr ) );
 | 
			
		||||
  m_sd = INVALID_SOCKET;
 | 
			
		||||
  m_family = af_inet;
 | 
			
		||||
  m_domain = pf_inet;
 | 
			
		||||
  m_type = sock_stream;
 | 
			
		||||
  m_protocol = tcp;
 | 
			
		||||
  m_port = 0;
 | 
			
		||||
  memset(&m_sockaddr, 0, sizeof(m_sockaddr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -55,7 +61,7 @@ Socket::~Socket()
 | 
			
		||||
 | 
			
		||||
bool Socket::setHostname(const std::string& host)
 | 
			
		||||
{
 | 
			
		||||
  _hostname = host;
 | 
			
		||||
  m_hostname = host;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -63,9 +69,9 @@ bool Socket::close()
 | 
			
		||||
{
 | 
			
		||||
  if (is_valid())
 | 
			
		||||
  {
 | 
			
		||||
    if (_sd != SOCKET_ERROR)
 | 
			
		||||
      closesocket(_sd);
 | 
			
		||||
    _sd = INVALID_SOCKET;
 | 
			
		||||
    if (m_sd != SOCKET_ERROR)
 | 
			
		||||
      closesocket(m_sd);
 | 
			
		||||
    m_sd = INVALID_SOCKET;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
@@ -75,7 +81,7 @@ bool Socket::create()
 | 
			
		||||
{
 | 
			
		||||
  close();
 | 
			
		||||
 | 
			
		||||
  if(!osInit())
 | 
			
		||||
  if (!osInit())
 | 
			
		||||
  {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -84,7 +90,7 @@ bool Socket::create()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool Socket::bind ( const unsigned short port )
 | 
			
		||||
bool Socket::bind(const unsigned short port)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  if (is_valid())
 | 
			
		||||
@@ -92,17 +98,17 @@ bool Socket::bind ( const unsigned short port )
 | 
			
		||||
    close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _sd = socket(_family, _type, _protocol);
 | 
			
		||||
  _port = port;
 | 
			
		||||
  _sockaddr.sin_family = (sa_family_t) _family;
 | 
			
		||||
  _sockaddr.sin_addr.s_addr = INADDR_ANY;  //listen to all
 | 
			
		||||
  _sockaddr.sin_port = htons( _port );
 | 
			
		||||
  m_sd = socket(m_family, m_type, m_protocol);
 | 
			
		||||
  m_port = port;
 | 
			
		||||
  m_sockaddr.sin_family = (sa_family_t)m_family;
 | 
			
		||||
  m_sockaddr.sin_addr.s_addr = INADDR_ANY; //listen to all
 | 
			
		||||
  m_sockaddr.sin_port = htons(m_port);
 | 
			
		||||
 | 
			
		||||
  int bind_return = ::bind(_sd, (sockaddr*)(&_sockaddr), sizeof(_sockaddr));
 | 
			
		||||
  int bind_return = ::bind(m_sd, (sockaddr*)(&m_sockaddr), sizeof(m_sockaddr));
 | 
			
		||||
 | 
			
		||||
  if ( bind_return == -1 )
 | 
			
		||||
  if (bind_return == -1)
 | 
			
		||||
  {
 | 
			
		||||
    errormessage( getLastError(), "Socket::bind" );
 | 
			
		||||
    errormessage(getLastError(), "Socket::bind");
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -118,13 +124,13 @@ bool Socket::listen() const
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int listen_return = ::listen (_sd, SOMAXCONN);
 | 
			
		||||
  int listen_return = ::listen(m_sd, SOMAXCONN);
 | 
			
		||||
  //This is defined as 5 in winsock.h, and 0x7FFFFFFF in winsock2.h.
 | 
			
		||||
  //linux 128//MAXCONNECTIONS =1
 | 
			
		||||
 | 
			
		||||
  if (listen_return == -1)
 | 
			
		||||
  {
 | 
			
		||||
    errormessage( getLastError(), "Socket::listen" );
 | 
			
		||||
    errormessage(getLastError(), "Socket::listen");
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -132,23 +138,23 @@ bool Socket::listen() const
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool Socket::accept ( Socket& new_socket ) const
 | 
			
		||||
bool Socket::accept(Socket& new_socket) const
 | 
			
		||||
{
 | 
			
		||||
  if (!is_valid())
 | 
			
		||||
  {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  socklen_t addr_length = sizeof( _sockaddr );
 | 
			
		||||
  new_socket._sd = ::accept(_sd, const_cast<sockaddr*>( (const sockaddr*) &_sockaddr), &addr_length );
 | 
			
		||||
  socklen_t addr_length = sizeof(m_sockaddr);
 | 
			
		||||
  new_socket.m_sd = ::accept(m_sd, const_cast<sockaddr*>((const sockaddr*)&m_sockaddr), &addr_length);
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_WINDOWS
 | 
			
		||||
  if (new_socket._sd == INVALID_SOCKET)
 | 
			
		||||
  if (new_socket.m_sd == INVALID_SOCKET)
 | 
			
		||||
#else
 | 
			
		||||
  if (new_socket._sd <= 0)
 | 
			
		||||
  if (new_socket.m_sd <= 0)
 | 
			
		||||
#endif
 | 
			
		||||
  {
 | 
			
		||||
    errormessage( getLastError(), "Socket::accept" );
 | 
			
		||||
    errormessage(getLastError(), "Socket::accept");
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -156,13 +162,13 @@ bool Socket::accept ( Socket& new_socket ) const
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int Socket::send ( const std::string& data )
 | 
			
		||||
int Socket::send(const std::string& data)
 | 
			
		||||
{
 | 
			
		||||
  return Socket::send( (const char*) data.c_str(), (const unsigned int) data.size());
 | 
			
		||||
  return Socket::send((const char*)data.c_str(), (const unsigned int)data.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int Socket::send ( const char* data, const unsigned int len )
 | 
			
		||||
int Socket::send(const char* data, const unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
  fd_set set_w, set_e;
 | 
			
		||||
  struct timeval tv;
 | 
			
		||||
@@ -179,10 +185,10 @@ int Socket::send ( const char* data, const unsigned int len )
 | 
			
		||||
 | 
			
		||||
  FD_ZERO(&set_w);
 | 
			
		||||
  FD_ZERO(&set_e);
 | 
			
		||||
  FD_SET(_sd, &set_w);
 | 
			
		||||
  FD_SET(_sd, &set_e);
 | 
			
		||||
  FD_SET(m_sd, &set_w);
 | 
			
		||||
  FD_SET(m_sd, &set_e);
 | 
			
		||||
 | 
			
		||||
  result = select(FD_SETSIZE, &set_w, NULL, &set_e, &tv);
 | 
			
		||||
  result = select(FD_SETSIZE, &set_w, nullptr, &set_e, &tv);
 | 
			
		||||
 | 
			
		||||
  if (result < 0)
 | 
			
		||||
  {
 | 
			
		||||
@@ -190,18 +196,18 @@ int Socket::send ( const char* data, const unsigned int len )
 | 
			
		||||
    close();
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  if (FD_ISSET(_sd, &set_w))
 | 
			
		||||
  if (FD_ISSET(m_sd, &set_w))
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Socket::send  - failed to send data");
 | 
			
		||||
    close();
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int status = ::send(_sd, data, len, 0 );
 | 
			
		||||
  int status = ::send(m_sd, data, len, 0);
 | 
			
		||||
 | 
			
		||||
  if (status == -1)
 | 
			
		||||
  {
 | 
			
		||||
    errormessage( getLastError(), "Socket::send");
 | 
			
		||||
    errormessage(getLastError(), "Socket::send");
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Socket::send  - failed to send data");
 | 
			
		||||
    close();
 | 
			
		||||
    return 0;
 | 
			
		||||
@@ -210,31 +216,31 @@ int Socket::send ( const char* data, const unsigned int len )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int Socket::sendto ( const char* data, unsigned int size, bool sendcompletebuffer)
 | 
			
		||||
int Socket::sendto(const char* data, unsigned int size, bool sendcompletebuffer)
 | 
			
		||||
{
 | 
			
		||||
  int sentbytes = 0;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  do
 | 
			
		||||
  {
 | 
			
		||||
    i = ::sendto(_sd, data, size, 0, (const struct sockaddr*) &_sockaddr, sizeof( _sockaddr ) );
 | 
			
		||||
    i = ::sendto(m_sd, data, size, 0, (const struct sockaddr*)&m_sockaddr, sizeof(m_sockaddr));
 | 
			
		||||
 | 
			
		||||
    if (i <= 0)
 | 
			
		||||
    {
 | 
			
		||||
      errormessage( getLastError(), "Socket::sendto");
 | 
			
		||||
      errormessage(getLastError(), "Socket::sendto");
 | 
			
		||||
      osCleanup();
 | 
			
		||||
      return i;
 | 
			
		||||
    }
 | 
			
		||||
    sentbytes += i;
 | 
			
		||||
  } while ( (sentbytes < (int) size) && (sendcompletebuffer == true));
 | 
			
		||||
  } while ((sentbytes < (int)size) && (sendcompletebuffer == true));
 | 
			
		||||
 | 
			
		||||
  return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int Socket::receive ( std::string& data, unsigned int minpacketsize ) const
 | 
			
		||||
int Socket::receive(std::string& data, unsigned int minpacketsize) const
 | 
			
		||||
{
 | 
			
		||||
  char * buf = NULL;
 | 
			
		||||
  char* buf = nullptr;
 | 
			
		||||
  int status = 0;
 | 
			
		||||
 | 
			
		||||
  if (!is_valid())
 | 
			
		||||
@@ -242,10 +248,10 @@ int Socket::receive ( std::string& data, unsigned int minpacketsize ) const
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  buf = new char [ minpacketsize + 1 ];
 | 
			
		||||
  memset ( buf, 0, minpacketsize + 1 );
 | 
			
		||||
  buf = new char[minpacketsize + 1];
 | 
			
		||||
  memset(buf, 0, minpacketsize + 1);
 | 
			
		||||
 | 
			
		||||
  status = receive( buf, minpacketsize, minpacketsize );
 | 
			
		||||
  status = receive(buf, minpacketsize, minpacketsize);
 | 
			
		||||
 | 
			
		||||
  data = buf;
 | 
			
		||||
 | 
			
		||||
@@ -255,7 +261,7 @@ int Socket::receive ( std::string& data, unsigned int minpacketsize ) const
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Receive until error or \n
 | 
			
		||||
bool Socket::ReadLine (string& line)
 | 
			
		||||
bool Socket::ReadLine(string& line)
 | 
			
		||||
{
 | 
			
		||||
  fd_set set_r, set_e;
 | 
			
		||||
  timeval timeout;
 | 
			
		||||
@@ -280,9 +286,9 @@ bool Socket::ReadLine (string& line)
 | 
			
		||||
    // fill with new data
 | 
			
		||||
    FD_ZERO(&set_r);
 | 
			
		||||
    FD_ZERO(&set_e);
 | 
			
		||||
    FD_SET(_sd, &set_r);
 | 
			
		||||
    FD_SET(_sd, &set_e);
 | 
			
		||||
    int result = select(FD_SETSIZE, &set_r, NULL, &set_e, &timeout);
 | 
			
		||||
    FD_SET(m_sd, &set_r);
 | 
			
		||||
    FD_SET(m_sd, &set_e);
 | 
			
		||||
    int result = select(FD_SETSIZE, &set_r, nullptr, &set_e, &timeout);
 | 
			
		||||
 | 
			
		||||
    if (result < 0)
 | 
			
		||||
    {
 | 
			
		||||
@@ -296,16 +302,20 @@ bool Socket::ReadLine (string& line)
 | 
			
		||||
    {
 | 
			
		||||
      if (retries != 0)
 | 
			
		||||
      {
 | 
			
		||||
         libKodi->Log(LOG_DEBUG, "%s: timeout waiting for response, retrying... (%i)", __FUNCTION__, retries);
 | 
			
		||||
        libKodi->Log(LOG_DEBUG, "%s: timeout waiting for response, retrying... (%i)", __FUNCTION__,
 | 
			
		||||
                     retries);
 | 
			
		||||
        retries--;
 | 
			
		||||
        continue;
 | 
			
		||||
      } else {
 | 
			
		||||
         libKodi->Log(LOG_DEBUG, "%s: timeout waiting for response. Aborting after 10 retries.", __FUNCTION__);
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        libKodi->Log(LOG_DEBUG, "%s: timeout waiting for response. Aborting after 10 retries.",
 | 
			
		||||
                     __FUNCTION__);
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result = recv(_sd, buffer, sizeof(buffer) - 1, 0);
 | 
			
		||||
    result = recv(m_sd, buffer, sizeof(buffer) - 1, 0);
 | 
			
		||||
    if (result < 0)
 | 
			
		||||
    {
 | 
			
		||||
      libKodi->Log(LOG_DEBUG, "%s: recv failed", __FUNCTION__);
 | 
			
		||||
@@ -322,39 +332,41 @@ bool Socket::ReadLine (string& line)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int Socket::receive ( std::string& data) const
 | 
			
		||||
int Socket::receive(std::string& data) const
 | 
			
		||||
{
 | 
			
		||||
  char buf[MAXRECV + 1];
 | 
			
		||||
  int status = 0;
 | 
			
		||||
 | 
			
		||||
  if ( !is_valid() )
 | 
			
		||||
  if (!is_valid())
 | 
			
		||||
  {
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  memset ( buf, 0, MAXRECV + 1 );
 | 
			
		||||
  status = receive( buf, MAXRECV, 0 );
 | 
			
		||||
  memset(buf, 0, MAXRECV + 1);
 | 
			
		||||
  status = receive(buf, MAXRECV, 0);
 | 
			
		||||
  data = buf;
 | 
			
		||||
 | 
			
		||||
  return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Socket::receive ( char* data, const unsigned int buffersize, const unsigned int minpacketsize ) const
 | 
			
		||||
int Socket::receive(char* data,
 | 
			
		||||
                    const unsigned int buffersize,
 | 
			
		||||
                    const unsigned int minpacketsize) const
 | 
			
		||||
{
 | 
			
		||||
  unsigned int receivedsize = 0;
 | 
			
		||||
 | 
			
		||||
  if ( !is_valid() )
 | 
			
		||||
  if (!is_valid())
 | 
			
		||||
  {
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while ( (receivedsize <= minpacketsize) && (receivedsize < buffersize) )
 | 
			
		||||
  while ((receivedsize <= minpacketsize) && (receivedsize < buffersize))
 | 
			
		||||
  {
 | 
			
		||||
    int status = ::recv(_sd, data+receivedsize, (buffersize - receivedsize), 0 );
 | 
			
		||||
    int status = ::recv(m_sd, data + receivedsize, (buffersize - receivedsize), 0);
 | 
			
		||||
 | 
			
		||||
    if ( status == SOCKET_ERROR )
 | 
			
		||||
    if (status == SOCKET_ERROR)
 | 
			
		||||
    {
 | 
			
		||||
      errormessage( getLastError(), "Socket::receive" );
 | 
			
		||||
      errormessage(getLastError(), "Socket::receive");
 | 
			
		||||
      return status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -365,35 +377,38 @@ int Socket::receive ( char* data, const unsigned int buffersize, const unsigned
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int Socket::recvfrom ( char* data, const int buffersize, struct sockaddr* from, socklen_t* fromlen) const
 | 
			
		||||
int Socket::recvfrom(char* data,
 | 
			
		||||
                     const int buffersize,
 | 
			
		||||
                     struct sockaddr* from,
 | 
			
		||||
                     socklen_t* fromlen) const
 | 
			
		||||
{
 | 
			
		||||
  int status = ::recvfrom(_sd, data, buffersize, 0, from, fromlen);
 | 
			
		||||
  int status = ::recvfrom(m_sd, data, buffersize, 0, from, fromlen);
 | 
			
		||||
 | 
			
		||||
  return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool Socket::connect ( const std::string& host, const unsigned short port )
 | 
			
		||||
bool Socket::connect(const std::string& host, const unsigned short port)
 | 
			
		||||
{
 | 
			
		||||
  close();
 | 
			
		||||
 | 
			
		||||
  if ( !setHostname( host ) )
 | 
			
		||||
  if (!setHostname(host))
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Socket::setHostname(%s) failed.\n", host.c_str());
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  _port = port;
 | 
			
		||||
  m_port = port;
 | 
			
		||||
 | 
			
		||||
  char strPort[15];
 | 
			
		||||
  snprintf(strPort, 15, "%hu", port);
 | 
			
		||||
 | 
			
		||||
  struct addrinfo hints;
 | 
			
		||||
  struct addrinfo* result = NULL;
 | 
			
		||||
  struct addrinfo *address = NULL;
 | 
			
		||||
  struct addrinfo* result = nullptr;
 | 
			
		||||
  struct addrinfo* address = nullptr;
 | 
			
		||||
  memset(&hints, 0, sizeof(hints));
 | 
			
		||||
  hints.ai_family = _family;
 | 
			
		||||
  hints.ai_socktype = _type;
 | 
			
		||||
  hints.ai_protocol = _protocol;
 | 
			
		||||
  hints.ai_family = m_family;
 | 
			
		||||
  hints.ai_socktype = m_type;
 | 
			
		||||
  hints.ai_protocol = m_protocol;
 | 
			
		||||
 | 
			
		||||
  int retval = getaddrinfo(host.c_str(), strPort, &hints, &result);
 | 
			
		||||
  if (retval != 0)
 | 
			
		||||
@@ -402,18 +417,18 @@ bool Socket::connect ( const std::string& host, const unsigned short port )
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (address = result; address != NULL; address = address->ai_next)
 | 
			
		||||
  for (address = result; address != nullptr; address = address->ai_next)
 | 
			
		||||
  {
 | 
			
		||||
    // Create the socket
 | 
			
		||||
    _sd = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
 | 
			
		||||
    m_sd = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
 | 
			
		||||
 | 
			
		||||
    if (_sd == INVALID_SOCKET)
 | 
			
		||||
    if (m_sd == INVALID_SOCKET)
 | 
			
		||||
    {
 | 
			
		||||
      errormessage(getLastError(), "Socket::create");
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int status = ::connect(_sd, address->ai_addr, address->ai_addrlen);
 | 
			
		||||
    int status = ::connect(m_sd, address->ai_addr, address->ai_addrlen);
 | 
			
		||||
    if (status == SOCKET_ERROR)
 | 
			
		||||
    {
 | 
			
		||||
      close();
 | 
			
		||||
@@ -426,7 +441,7 @@ bool Socket::connect ( const std::string& host, const unsigned short port )
 | 
			
		||||
 | 
			
		||||
  freeaddrinfo(result);
 | 
			
		||||
 | 
			
		||||
  if (address == NULL)
 | 
			
		||||
  if (address == nullptr)
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Socket::connect %s:%u\n", host.c_str(), port);
 | 
			
		||||
    errormessage(getLastError(), "Socket::connect");
 | 
			
		||||
@@ -439,30 +454,30 @@ bool Socket::connect ( const std::string& host, const unsigned short port )
 | 
			
		||||
 | 
			
		||||
bool Socket::reconnect()
 | 
			
		||||
{
 | 
			
		||||
  if ( is_valid() )
 | 
			
		||||
  if (is_valid())
 | 
			
		||||
  {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return connect(_hostname, _port);
 | 
			
		||||
  return connect(m_hostname, m_port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Socket::is_valid() const
 | 
			
		||||
{
 | 
			
		||||
  return (_sd != INVALID_SOCKET);
 | 
			
		||||
  return (m_sd != INVALID_SOCKET);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(TARGET_WINDOWS)
 | 
			
		||||
bool Socket::set_non_blocking ( const bool b )
 | 
			
		||||
bool Socket::set_non_blocking(const bool b)
 | 
			
		||||
{
 | 
			
		||||
  u_long iMode;
 | 
			
		||||
 | 
			
		||||
  if ( b )
 | 
			
		||||
  if (b)
 | 
			
		||||
    iMode = 1; // enable non_blocking
 | 
			
		||||
  else
 | 
			
		||||
    iMode = 0; // disable non_blocking
 | 
			
		||||
 | 
			
		||||
  if (ioctlsocket(_sd, FIONBIO, &iMode) == -1)
 | 
			
		||||
  if (ioctlsocket(m_sd, FIONBIO, &iMode) == -1)
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Socket::set_non_blocking - Can't set socket condition to: %i", iMode);
 | 
			
		||||
    return false;
 | 
			
		||||
@@ -471,9 +486,9 @@ bool Socket::set_non_blocking ( const bool b )
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Socket::errormessage( int errnum, const char* functionname) const
 | 
			
		||||
void Socket::errormessage(int errnum, const char* functionname) const
 | 
			
		||||
{
 | 
			
		||||
  const char* errmsg = NULL;
 | 
			
		||||
  const char* errmsg = nullptr;
 | 
			
		||||
 | 
			
		||||
  switch (errnum)
 | 
			
		||||
  {
 | 
			
		||||
@@ -569,15 +584,15 @@ bool Socket::osInit()
 | 
			
		||||
{
 | 
			
		||||
  win_usage_count++;
 | 
			
		||||
  // initialize winsock:
 | 
			
		||||
  if (WSAStartup(MAKEWORD(2,2),&_wsaData) != 0)
 | 
			
		||||
  if (WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0)
 | 
			
		||||
  {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  WORD wVersionRequested = MAKEWORD(2,2);
 | 
			
		||||
  WORD wVersionRequested = MAKEWORD(2, 2);
 | 
			
		||||
 | 
			
		||||
  // check version
 | 
			
		||||
  if (_wsaData.wVersion != wVersionRequested)
 | 
			
		||||
  if (m_wsaData.wVersion != wVersionRequested)
 | 
			
		||||
  {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -588,30 +603,30 @@ bool Socket::osInit()
 | 
			
		||||
void Socket::osCleanup()
 | 
			
		||||
{
 | 
			
		||||
  win_usage_count--;
 | 
			
		||||
  if(win_usage_count == 0)
 | 
			
		||||
  if (win_usage_count == 0)
 | 
			
		||||
  {
 | 
			
		||||
    WSACleanup();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
			
		||||
bool Socket::set_non_blocking ( const bool b )
 | 
			
		||||
bool Socket::set_non_blocking(const bool b)
 | 
			
		||||
{
 | 
			
		||||
  int opts;
 | 
			
		||||
 | 
			
		||||
  opts = fcntl(_sd, F_GETFL);
 | 
			
		||||
  opts = fcntl(m_sd, F_GETFL);
 | 
			
		||||
 | 
			
		||||
  if ( opts < 0 )
 | 
			
		||||
  if (opts < 0)
 | 
			
		||||
  {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( b )
 | 
			
		||||
    opts = ( opts | O_NONBLOCK );
 | 
			
		||||
  if (b)
 | 
			
		||||
    opts = (opts | O_NONBLOCK);
 | 
			
		||||
  else
 | 
			
		||||
    opts = ( opts & ~O_NONBLOCK );
 | 
			
		||||
    opts = (opts & ~O_NONBLOCK);
 | 
			
		||||
 | 
			
		||||
  if(fcntl (_sd , F_SETFL, opts) == -1)
 | 
			
		||||
  if (fcntl(m_sd, F_SETFL, opts) == -1)
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Socket::set_non_blocking - Can't set socket flags to: %i", opts);
 | 
			
		||||
    return false;
 | 
			
		||||
@@ -619,11 +634,11 @@ bool Socket::set_non_blocking ( const bool b )
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Socket::errormessage( int errnum, const char* functionname) const
 | 
			
		||||
void Socket::errormessage(int errnum, const char* functionname) const
 | 
			
		||||
{
 | 
			
		||||
  const char* errmsg = NULL;
 | 
			
		||||
  const char* errmsg = nullptr;
 | 
			
		||||
 | 
			
		||||
  switch ( errnum )
 | 
			
		||||
  switch (errnum)
 | 
			
		||||
  {
 | 
			
		||||
    case EAGAIN: //same as EWOULDBLOCK
 | 
			
		||||
      errmsg = "EAGAIN: The socket is marked non-blocking and the requested operation would block";
 | 
			
		||||
@@ -650,7 +665,8 @@ void Socket::errormessage( int errnum, const char* functionname) const
 | 
			
		||||
      errmsg = "ENOTSOCK: The argument is not a valid socket";
 | 
			
		||||
      break;
 | 
			
		||||
    case EMSGSIZE:
 | 
			
		||||
      errmsg = "EMSGSIZE: The socket requires that message be sent atomically, and the size of the message to be sent made this impossible";
 | 
			
		||||
      errmsg = "EMSGSIZE: The socket requires that message be sent atomically, and the size of the "
 | 
			
		||||
               "message to be sent made this impossible";
 | 
			
		||||
      break;
 | 
			
		||||
    case ENOBUFS:
 | 
			
		||||
      errmsg = "ENOBUFS: The output queue for a network interface was full";
 | 
			
		||||
@@ -662,7 +678,8 @@ void Socket::errormessage( int errnum, const char* functionname) const
 | 
			
		||||
      errmsg = "EPIPE: The local end has been shut down on a connection oriented socket";
 | 
			
		||||
      break;
 | 
			
		||||
    case EPROTONOSUPPORT:
 | 
			
		||||
      errmsg = "EPROTONOSUPPORT: The protocol type or the specified protocol is not supported within this domain";
 | 
			
		||||
      errmsg = "EPROTONOSUPPORT: The protocol type or the specified protocol is not supported "
 | 
			
		||||
               "within this domain";
 | 
			
		||||
      break;
 | 
			
		||||
    case EAFNOSUPPORT:
 | 
			
		||||
      errmsg = "EAFNOSUPPORT: The implementation does not support the specified address family";
 | 
			
		||||
@@ -674,13 +691,16 @@ void Socket::errormessage( int errnum, const char* functionname) const
 | 
			
		||||
      errmsg = "EMFILE: Process file table overflow";
 | 
			
		||||
      break;
 | 
			
		||||
    case EACCES:
 | 
			
		||||
      errmsg = "EACCES: Permission to create a socket of the specified type and/or protocol is denied";
 | 
			
		||||
      errmsg =
 | 
			
		||||
          "EACCES: Permission to create a socket of the specified type and/or protocol is denied";
 | 
			
		||||
      break;
 | 
			
		||||
    case ECONNREFUSED:
 | 
			
		||||
      errmsg = "ECONNREFUSED: A remote host refused to allow the network connection (typically because it is not running the requested service)";
 | 
			
		||||
      errmsg = "ECONNREFUSED: A remote host refused to allow the network connection (typically "
 | 
			
		||||
               "because it is not running the requested service)";
 | 
			
		||||
      break;
 | 
			
		||||
    case ENOTCONN:
 | 
			
		||||
      errmsg = "ENOTCONN: The socket is associated with a connection-oriented protocol and has not been connected";
 | 
			
		||||
      errmsg = "ENOTCONN: The socket is associated with a connection-oriented protocol and has not "
 | 
			
		||||
               "been connected";
 | 
			
		||||
      break;
 | 
			
		||||
    //case E:
 | 
			
		||||
    //	errmsg = "";
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										178
									
								
								src/Socket.h
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								src/Socket.h
									
									
									
									
									
								
							@@ -10,57 +10,57 @@
 | 
			
		||||
 | 
			
		||||
//Include platform specific datatypes, header files, defines and constants:
 | 
			
		||||
#if defined TARGET_WINDOWS
 | 
			
		||||
  #define WIN32_LEAN_AND_MEAN           // Enable LEAN_AND_MEAN support
 | 
			
		||||
  #pragma warning(disable:4005) // Disable "warning C4005: '_WINSOCKAPI_' : macro redefinition"
 | 
			
		||||
  #include <winsock2.h>
 | 
			
		||||
  #include <WS2tcpip.h>
 | 
			
		||||
  #pragma warning(default:4005)
 | 
			
		||||
  #include <windows.h>
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN // Enable LEAN_AND_MEAN support
 | 
			
		||||
#pragma warning(disable : 4005) // Disable "warning C4005: '_WINSOCKAPI_' : macro redefinition"
 | 
			
		||||
#include <WS2tcpip.h>
 | 
			
		||||
#include <winsock2.h>
 | 
			
		||||
#pragma warning(default : 4005)
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
 | 
			
		||||
  #ifndef NI_MAXHOST
 | 
			
		||||
    #define NI_MAXHOST 1025
 | 
			
		||||
  #endif
 | 
			
		||||
#ifndef NI_MAXHOST
 | 
			
		||||
#define NI_MAXHOST 1025
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  #ifndef socklen_t
 | 
			
		||||
    typedef int socklen_t;
 | 
			
		||||
  #endif
 | 
			
		||||
  #ifndef ipaddr_t
 | 
			
		||||
    typedef unsigned long ipaddr_t;
 | 
			
		||||
  #endif
 | 
			
		||||
  #ifndef port_t
 | 
			
		||||
    typedef unsigned short port_t;
 | 
			
		||||
  #endif
 | 
			
		||||
  #ifndef sa_family_t
 | 
			
		||||
    #define sa_family_t ADDRESS_FAMILY
 | 
			
		||||
  #endif
 | 
			
		||||
#ifndef socklen_t
 | 
			
		||||
typedef int socklen_t;
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef ipaddr_t
 | 
			
		||||
typedef unsigned long ipaddr_t;
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef port_t
 | 
			
		||||
typedef unsigned short port_t;
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef sa_family_t
 | 
			
		||||
#define sa_family_t ADDRESS_FAMILY
 | 
			
		||||
#endif
 | 
			
		||||
#elif defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
			
		||||
#ifdef SOCKADDR_IN
 | 
			
		||||
#undef SOCKADDR_IN
 | 
			
		||||
#endif
 | 
			
		||||
  #include <sys/types.h>     /* for socket,connect */
 | 
			
		||||
  #include <sys/socket.h>    /* for socket,connect */
 | 
			
		||||
  #include <sys/un.h>        /* for Unix socket */
 | 
			
		||||
  #include <arpa/inet.h>     /* for inet_pton */
 | 
			
		||||
  #include <netdb.h>         /* for gethostbyname */
 | 
			
		||||
  #include <netinet/in.h>    /* for htons */
 | 
			
		||||
  #include <unistd.h>        /* for read, write, close */
 | 
			
		||||
  #include <errno.h>
 | 
			
		||||
  #include <fcntl.h>
 | 
			
		||||
#include <arpa/inet.h> /* for inet_pton */
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <netdb.h> /* for gethostbyname */
 | 
			
		||||
#include <netinet/in.h> /* for htons */
 | 
			
		||||
#include <sys/socket.h> /* for socket,connect */
 | 
			
		||||
#include <sys/types.h> /* for socket,connect */
 | 
			
		||||
#include <sys/un.h> /* for Unix socket */
 | 
			
		||||
#include <unistd.h> /* for read, write, close */
 | 
			
		||||
 | 
			
		||||
  typedef int SOCKET;
 | 
			
		||||
  typedef sockaddr SOCKADDR;
 | 
			
		||||
  typedef sockaddr_in SOCKADDR_IN;
 | 
			
		||||
  #ifndef INVALID_SOCKET
 | 
			
		||||
  #define INVALID_SOCKET (-1)
 | 
			
		||||
  #endif
 | 
			
		||||
  #define SOCKET_ERROR (-1)
 | 
			
		||||
typedef int SOCKET;
 | 
			
		||||
typedef sockaddr SOCKADDR;
 | 
			
		||||
typedef sockaddr_in SOCKADDR_IN;
 | 
			
		||||
#ifndef INVALID_SOCKET
 | 
			
		||||
#define INVALID_SOCKET (-1)
 | 
			
		||||
#endif
 | 
			
		||||
#define SOCKET_ERROR (-1)
 | 
			
		||||
 | 
			
		||||
  #define closesocket(sd) ::close(sd)
 | 
			
		||||
#define closesocket(sd) ::close(sd)
 | 
			
		||||
#else
 | 
			
		||||
  #error Platform specific socket support is not yet available on this platform!
 | 
			
		||||
#error Platform specific socket support is not yet available on this platform!
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace OCTO
 | 
			
		||||
@@ -78,10 +78,10 @@ enum SocketFamily
 | 
			
		||||
 | 
			
		||||
enum SocketDomain
 | 
			
		||||
{
 | 
			
		||||
  #if defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
			
		||||
#if defined TARGET_LINUX || defined TARGET_DARWIN || defined TARGET_FREEBSD
 | 
			
		||||
  pf_unix = PF_UNIX,
 | 
			
		||||
  pf_local = PF_LOCAL,
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
  pf_inet = PF_INET
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -99,8 +99,7 @@ enum SocketProtocol
 | 
			
		||||
 | 
			
		||||
class Socket
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  /*!
 | 
			
		||||
   * An unconnected socket may be created directly on the local
 | 
			
		||||
   * machine. The socket type (SOCK_STREAM, SOCK_DGRAM) and
 | 
			
		||||
@@ -113,7 +112,10 @@ class Socket
 | 
			
		||||
   * \param type base type and protocol family of the socket.
 | 
			
		||||
   * \param protocol specific protocol to apply.
 | 
			
		||||
   */
 | 
			
		||||
    Socket(const enum SocketFamily family, const enum SocketDomain domain, const enum SocketType type, const enum SocketProtocol protocol = tcp);
 | 
			
		||||
  Socket(const enum SocketFamily family,
 | 
			
		||||
         const enum SocketDomain domain,
 | 
			
		||||
         const enum SocketType type,
 | 
			
		||||
         const enum SocketProtocol protocol = tcp);
 | 
			
		||||
  Socket(void);
 | 
			
		||||
  virtual ~Socket();
 | 
			
		||||
 | 
			
		||||
@@ -123,48 +125,33 @@ class Socket
 | 
			
		||||
   * Socket setFamily
 | 
			
		||||
   * \param family    Can be af_inet or af_inet6. Default: af_inet
 | 
			
		||||
   */
 | 
			
		||||
    void setFamily(const enum SocketFamily family)
 | 
			
		||||
    {
 | 
			
		||||
      _family = family;
 | 
			
		||||
    };
 | 
			
		||||
  void setFamily(const enum SocketFamily family) { m_family = family; };
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket setDomain
 | 
			
		||||
   * \param domain    Can be pf_unix, pf_local, pf_inet or pf_inet6. Default: pf_inet
 | 
			
		||||
   */
 | 
			
		||||
    void setDomain(const enum SocketDomain domain)
 | 
			
		||||
    {
 | 
			
		||||
      _domain = domain;
 | 
			
		||||
    };
 | 
			
		||||
  void setDomain(const enum SocketDomain domain) { m_domain = domain; };
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket setType
 | 
			
		||||
   * \param type    Can be sock_stream or sock_dgram. Default: sock_stream.
 | 
			
		||||
   */
 | 
			
		||||
    void setType(const enum SocketType type)
 | 
			
		||||
    {
 | 
			
		||||
      _type = type;
 | 
			
		||||
    };
 | 
			
		||||
  void setType(const enum SocketType type) { m_type = type; };
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket setProtocol
 | 
			
		||||
   * \param protocol    Can be tcp or udp. Default: tcp.
 | 
			
		||||
   */
 | 
			
		||||
    void setProtocol(const enum SocketProtocol protocol)
 | 
			
		||||
    {
 | 
			
		||||
      _protocol = protocol;
 | 
			
		||||
    };
 | 
			
		||||
  void setProtocol(const enum SocketProtocol protocol) { m_protocol = protocol; };
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket setPort
 | 
			
		||||
   * \param port    port number for socket communication
 | 
			
		||||
   */
 | 
			
		||||
    void setPort (const unsigned short port)
 | 
			
		||||
    {
 | 
			
		||||
      _sockaddr.sin_port = htons ( port );
 | 
			
		||||
    };
 | 
			
		||||
  void setPort(const unsigned short port) { m_sockaddr.sin_port = htons(port); };
 | 
			
		||||
 | 
			
		||||
    bool setHostname ( const std::string& host );
 | 
			
		||||
  bool setHostname(const std::string& host);
 | 
			
		||||
 | 
			
		||||
  // Server initialization
 | 
			
		||||
 | 
			
		||||
@@ -185,12 +172,12 @@ class Socket
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket bind
 | 
			
		||||
   */
 | 
			
		||||
    bool bind ( const unsigned short port );
 | 
			
		||||
  bool bind(const unsigned short port);
 | 
			
		||||
  bool listen() const;
 | 
			
		||||
    bool accept ( Socket& socket ) const;
 | 
			
		||||
  bool accept(Socket& socket) const;
 | 
			
		||||
 | 
			
		||||
  // Client initialization
 | 
			
		||||
    bool connect ( const std::string& host, const unsigned short port );
 | 
			
		||||
  bool connect(const std::string& host, const unsigned short port);
 | 
			
		||||
 | 
			
		||||
  bool reconnect();
 | 
			
		||||
 | 
			
		||||
@@ -202,7 +189,7 @@ class Socket
 | 
			
		||||
   * \param data    Reference to a std::string with the data to transmit
 | 
			
		||||
   * \return    Number of bytes send or -1 in case of an error
 | 
			
		||||
   */
 | 
			
		||||
    int send ( const std::string& data );
 | 
			
		||||
  int send(const std::string& data);
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket send function
 | 
			
		||||
@@ -211,7 +198,7 @@ class Socket
 | 
			
		||||
   * \param size    Length of the data to transmit
 | 
			
		||||
   * \return    Number of bytes send or -1 in case of an error
 | 
			
		||||
   */
 | 
			
		||||
    int send ( const char* data, const unsigned int size );
 | 
			
		||||
  int send(const char* data, const unsigned int size);
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket sendto function
 | 
			
		||||
@@ -221,7 +208,7 @@ class Socket
 | 
			
		||||
   * \param sendcompletebuffer    If 'true': do not return until the complete buffer is transmitted
 | 
			
		||||
   * \return    Number of bytes send or -1 in case of an error
 | 
			
		||||
   */
 | 
			
		||||
    int sendto ( const char* data, unsigned int size, bool sendcompletebuffer = false);
 | 
			
		||||
  int sendto(const char* data, unsigned int size, bool sendcompletebuffer = false);
 | 
			
		||||
  // Data Receive
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
@@ -231,7 +218,7 @@ class Socket
 | 
			
		||||
   * \param minpacketsize    The minimum number of bytes that should be received before returning from this function
 | 
			
		||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
			
		||||
   */
 | 
			
		||||
    int receive ( std::string& data, unsigned int minpacketsize ) const;
 | 
			
		||||
  int receive(std::string& data, unsigned int minpacketsize) const;
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket receive function
 | 
			
		||||
@@ -239,7 +226,7 @@ class Socket
 | 
			
		||||
   * \param data    Reference to a std::string for storage of the received data.
 | 
			
		||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
			
		||||
   */
 | 
			
		||||
    int receive ( std::string& data ) const;
 | 
			
		||||
  int receive(std::string& data) const;
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket receive function
 | 
			
		||||
@@ -249,7 +236,7 @@ class Socket
 | 
			
		||||
   * \param minpacketsize    Specifies the minimum number of bytes that need to be received before returning
 | 
			
		||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
			
		||||
   */
 | 
			
		||||
    int receive ( char* data, const unsigned int buffersize, const unsigned int minpacketsize ) const;
 | 
			
		||||
  int receive(char* data, const unsigned int buffersize, const unsigned int minpacketsize) const;
 | 
			
		||||
 | 
			
		||||
  /*!
 | 
			
		||||
   * Socket recvfrom function
 | 
			
		||||
@@ -260,33 +247,36 @@ class Socket
 | 
			
		||||
   * \param fromlen    Optional, only required if 'from' is given: length of from struct
 | 
			
		||||
   * \return    Number of bytes received or SOCKET_ERROR
 | 
			
		||||
   */
 | 
			
		||||
    int recvfrom ( char* data, const int buffersize, struct sockaddr* from = NULL, socklen_t* fromlen = NULL) const;
 | 
			
		||||
  int recvfrom(char* data,
 | 
			
		||||
               const int buffersize,
 | 
			
		||||
               struct sockaddr* from = nullptr,
 | 
			
		||||
               socklen_t* fromlen = nullptr) const;
 | 
			
		||||
 | 
			
		||||
    bool set_non_blocking ( const bool );
 | 
			
		||||
  bool set_non_blocking(const bool);
 | 
			
		||||
 | 
			
		||||
    bool ReadLine (std::string& line);
 | 
			
		||||
  bool ReadLine(std::string& line);
 | 
			
		||||
 | 
			
		||||
  bool is_valid() const;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
private:
 | 
			
		||||
  SOCKET m_sd; ///< Socket Descriptor
 | 
			
		||||
  SOCKADDR_IN m_sockaddr; ///< Socket Address
 | 
			
		||||
  //struct addrinfo* m_addrinfo;         ///< Socket address info
 | 
			
		||||
  std::string m_hostname; ///< Hostname
 | 
			
		||||
  unsigned short m_port; ///< Port number
 | 
			
		||||
 | 
			
		||||
    SOCKET _sd;                         ///< Socket Descriptor
 | 
			
		||||
    SOCKADDR_IN _sockaddr;              ///< Socket Address
 | 
			
		||||
    //struct addrinfo* _addrinfo;         ///< Socket address info
 | 
			
		||||
    std::string _hostname;              ///< Hostname
 | 
			
		||||
    unsigned short _port;               ///< Port number
 | 
			
		||||
  enum SocketFamily m_family; ///< Socket Address Family
 | 
			
		||||
  enum SocketProtocol m_protocol; ///< Socket Protocol
 | 
			
		||||
  enum SocketType m_type; ///< Socket Type
 | 
			
		||||
  enum SocketDomain m_domain; ///< Socket domain
 | 
			
		||||
 | 
			
		||||
    enum SocketFamily _family;          ///< Socket Address Family
 | 
			
		||||
    enum SocketProtocol _protocol;      ///< Socket Protocol
 | 
			
		||||
    enum SocketType _type;              ///< Socket Type
 | 
			
		||||
    enum SocketDomain _domain;          ///< Socket domain
 | 
			
		||||
#ifdef TARGET_WINDOWS
 | 
			
		||||
  WSADATA m_wsaData; ///< Windows Socket data
 | 
			
		||||
  static int
 | 
			
		||||
      win_usage_count; ///< Internal Windows usage counter used to prevent a global WSACleanup when more than one Socket object is used
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    #ifdef TARGET_WINDOWS
 | 
			
		||||
      WSADATA _wsaData;                 ///< Windows Socket data
 | 
			
		||||
      static int win_usage_count;       ///< Internal Windows usage counter used to prevent a global WSACleanup when more than one Socket object is used
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    void errormessage( int errornum, const char* functionname = NULL) const;
 | 
			
		||||
  void errormessage(int errornum, const char* functionname = nullptr) const;
 | 
			
		||||
  int getLastError(void) const;
 | 
			
		||||
  bool osInit();
 | 
			
		||||
  void osCleanup();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										336
									
								
								src/client.cpp
									
									
									
									
									
								
							
							
						
						
									
										336
									
								
								src/client.cpp
									
									
									
									
									
								
							@@ -9,13 +9,14 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "client.h"
 | 
			
		||||
#include <kodi/xbmc_pvr_dll.h>
 | 
			
		||||
#include <kodi/libXBMC_addon.h>
 | 
			
		||||
#include <p8-platform/util/util.h>
 | 
			
		||||
 | 
			
		||||
#include "OctonetData.h"
 | 
			
		||||
#include "rtsp_client.hpp"
 | 
			
		||||
 | 
			
		||||
#include <kodi/libXBMC_addon.h>
 | 
			
		||||
#include <kodi/xbmc_pvr_dll.h>
 | 
			
		||||
#include <p8-platform/util/util.h>
 | 
			
		||||
 | 
			
		||||
using namespace ADDON;
 | 
			
		||||
 | 
			
		||||
/* setting variables with defaults */
 | 
			
		||||
@@ -23,38 +24,41 @@ std::string octonetAddress = "";
 | 
			
		||||
 | 
			
		||||
/* internal state variables */
 | 
			
		||||
ADDON_STATUS addonStatus = ADDON_STATUS_UNKNOWN;
 | 
			
		||||
CHelper_libXBMC_addon *libKodi = NULL;
 | 
			
		||||
CHelper_libXBMC_pvr *pvr = NULL;
 | 
			
		||||
CHelper_libXBMC_addon* libKodi = nullptr;
 | 
			
		||||
CHelper_libXBMC_pvr* pvr = nullptr;
 | 
			
		||||
 | 
			
		||||
OctonetData *data = NULL;
 | 
			
		||||
OctonetData* data = nullptr;
 | 
			
		||||
 | 
			
		||||
/* KODI Core Addon functions
 | 
			
		||||
 * see xbmc_addon_dll.h */
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
void ADDON_ReadSettings(void)
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  void ADDON_ReadSettings(void)
 | 
			
		||||
  {
 | 
			
		||||
    char buffer[2048];
 | 
			
		||||
    if (libKodi->GetSetting("octonetAddress", &buffer))
 | 
			
		||||
      octonetAddress = buffer;
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
ADDON_STATUS ADDON_Create(void* callbacks, const char* globalApiVersion, void* props)
 | 
			
		||||
{
 | 
			
		||||
	if (callbacks == NULL || props == NULL)
 | 
			
		||||
  ADDON_STATUS ADDON_Create(void* callbacks, const char* globalApiVersion, void* props)
 | 
			
		||||
  {
 | 
			
		||||
    if (callbacks == nullptr || props == nullptr)
 | 
			
		||||
      return ADDON_STATUS_UNKNOWN;
 | 
			
		||||
 | 
			
		||||
	AddonProperties_PVR *pvrprops = (AddonProperties_PVR*)props;
 | 
			
		||||
    AddonProperties_PVR* pvrprops = (AddonProperties_PVR*)props;
 | 
			
		||||
    libKodi = new CHelper_libXBMC_addon;
 | 
			
		||||
	if (!libKodi->RegisterMe(callbacks)) {
 | 
			
		||||
    if (!libKodi->RegisterMe(callbacks))
 | 
			
		||||
    {
 | 
			
		||||
      libKodi->Log(LOG_ERROR, "%s: Failed to register octonet addon", __func__);
 | 
			
		||||
      SAFE_DELETE(libKodi);
 | 
			
		||||
      return ADDON_STATUS_PERMANENT_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pvr = new CHelper_libXBMC_pvr;
 | 
			
		||||
	if (!pvr->RegisterMe(callbacks)) {
 | 
			
		||||
    if (!pvr->RegisterMe(callbacks))
 | 
			
		||||
    {
 | 
			
		||||
      libKodi->Log(LOG_ERROR, "%s: Failed to register octonet pvr addon", __func__);
 | 
			
		||||
      SAFE_DELETE(pvr);
 | 
			
		||||
      SAFE_DELETE(libKodi);
 | 
			
		||||
@@ -68,27 +72,23 @@ ADDON_STATUS ADDON_Create(void* callbacks, const char* globalApiVersion, void* p
 | 
			
		||||
 | 
			
		||||
    addonStatus = ADDON_STATUS_OK;
 | 
			
		||||
    return addonStatus;
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
void ADDON_Destroy()
 | 
			
		||||
{
 | 
			
		||||
  void ADDON_Destroy()
 | 
			
		||||
  {
 | 
			
		||||
    delete pvr;
 | 
			
		||||
    delete libKodi;
 | 
			
		||||
    addonStatus = ADDON_STATUS_UNKNOWN;
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
ADDON_STATUS ADDON_GetStatus()
 | 
			
		||||
{
 | 
			
		||||
	return addonStatus;
 | 
			
		||||
}
 | 
			
		||||
  ADDON_STATUS ADDON_GetStatus() { return addonStatus; }
 | 
			
		||||
 | 
			
		||||
ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue)
 | 
			
		||||
{
 | 
			
		||||
  ADDON_STATUS ADDON_SetSetting(const char* settingName, const void* settingValue)
 | 
			
		||||
  {
 | 
			
		||||
    /* For simplicity do a full addon restart whenever settings are
 | 
			
		||||
	 * changed */
 | 
			
		||||
    return ADDON_STATUS_NEED_RESTART;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -97,8 +97,8 @@ ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue)
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
PVR_ERROR GetCapabilities(PVR_ADDON_CAPABILITIES *pCapabilities)
 | 
			
		||||
{
 | 
			
		||||
  PVR_ERROR GetCapabilities(PVR_ADDON_CAPABILITIES* pCapabilities)
 | 
			
		||||
  {
 | 
			
		||||
    pCapabilities->bSupportsTV = true;
 | 
			
		||||
    pCapabilities->bSupportsRadio = true;
 | 
			
		||||
    pCapabilities->bSupportsChannelGroups = true;
 | 
			
		||||
@@ -109,166 +109,192 @@ PVR_ERROR GetCapabilities(PVR_ADDON_CAPABILITIES *pCapabilities)
 | 
			
		||||
    pCapabilities->bSupportsDescrambleInfo = false;
 | 
			
		||||
 | 
			
		||||
    return PVR_ERROR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
const char* GetBackendName(void)
 | 
			
		||||
{
 | 
			
		||||
	return "Digital Devices Octopus NET Client";
 | 
			
		||||
}
 | 
			
		||||
  const char* GetBackendName(void) { return "Digital Devices Octopus NET Client"; }
 | 
			
		||||
 | 
			
		||||
const char* GetBackendVersion(void)
 | 
			
		||||
{
 | 
			
		||||
	return STR(OCTONET_VERSION);
 | 
			
		||||
}
 | 
			
		||||
  const char* GetBackendVersion(void) { return STR(OCTONET_VERSION); }
 | 
			
		||||
 | 
			
		||||
const char* GetConnectionString(void)
 | 
			
		||||
{
 | 
			
		||||
  const char* GetConnectionString(void)
 | 
			
		||||
  {
 | 
			
		||||
    return "connected"; // FIXME: translate?
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR CallMenuHook(const PVR_MENUHOOK& menuhook, const PVR_MENUHOOK_DATA &item) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR CallMenuHook(const PVR_MENUHOOK& menuhook, const PVR_MENUHOOK_DATA& item)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
void OnSystemSleep() {
 | 
			
		||||
  void OnSystemSleep()
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_INFO, "Received event: %s", __FUNCTION__);
 | 
			
		||||
    // FIXME: Disconnect?
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
void OnSystemWake() {
 | 
			
		||||
  void OnSystemWake()
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_INFO, "Received event: %s", __FUNCTION__);
 | 
			
		||||
    // FIXME:Reconnect?
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
void OnPowerSavingActivated() {}
 | 
			
		||||
void OnPowerSavingDeactivated() {}
 | 
			
		||||
  void OnPowerSavingActivated() {}
 | 
			
		||||
  void OnPowerSavingDeactivated() {}
 | 
			
		||||
 | 
			
		||||
/* EPG */
 | 
			
		||||
PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, int iChannelUid, time_t iStart, time_t iEnd)
 | 
			
		||||
{
 | 
			
		||||
  /* EPG */
 | 
			
		||||
  PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, int iChannelUid, time_t iStart, time_t iEnd)
 | 
			
		||||
  {
 | 
			
		||||
    return data->getEPG(handle, iChannelUid, iStart, iEnd);
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
PVR_ERROR IsEPGTagRecordable(const EPG_TAG*, bool*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR IsEPGTagPlayable(const EPG_TAG*, bool*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR IsEPGTagRecordable(const EPG_TAG*, bool*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR IsEPGTagPlayable(const EPG_TAG*, bool*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
/* Channel groups */
 | 
			
		||||
int GetChannelGroupsAmount(void)
 | 
			
		||||
{
 | 
			
		||||
	return data->getGroupCount();
 | 
			
		||||
}
 | 
			
		||||
  /* Channel groups */
 | 
			
		||||
  int GetChannelGroupsAmount(void) { return data->getGroupCount(); }
 | 
			
		||||
 | 
			
		||||
PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
{
 | 
			
		||||
  PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
  {
 | 
			
		||||
    return data->getGroups(handle, bRadio);
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group)
 | 
			
		||||
{
 | 
			
		||||
  PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group)
 | 
			
		||||
  {
 | 
			
		||||
    return data->getGroupMembers(handle, group);
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
/* Channels */
 | 
			
		||||
PVR_ERROR OpenDialogChannelScan(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  /* Channels */
 | 
			
		||||
  PVR_ERROR OpenDialogChannelScan(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
int GetChannelsAmount(void)
 | 
			
		||||
{
 | 
			
		||||
	return data->getChannelCount();
 | 
			
		||||
}
 | 
			
		||||
  int GetChannelsAmount(void) { return data->getChannelCount(); }
 | 
			
		||||
 | 
			
		||||
PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
{
 | 
			
		||||
  PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio)
 | 
			
		||||
  {
 | 
			
		||||
    return data->getChannels(handle, bRadio);
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
PVR_ERROR DeleteChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR RenameChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR DeleteChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR RenameChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL& channel)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
/* Recordings */
 | 
			
		||||
int GetRecordingsAmount(bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR DeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR RenameRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR SetRecordingLifetime(const PVR_RECORDING*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING& recording, int count) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastplayedposition) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
int GetRecordingLastPlayedPosition(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY edl[], int *size) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetRecordingSize(const PVR_RECORDING* recording, int64_t* sizeInBytes) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetTimerTypes(PVR_TIMER_TYPE types[], int *size) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
int GetTimersAmount(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetTimers(ADDON_HANDLE handle) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR AddTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR DeleteTimer(const PVR_TIMER& timer, bool bForceDelete) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR UpdateTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  /* Recordings */
 | 
			
		||||
  int GetRecordingsAmount(bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR DeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR RenameRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR SetRecordingLifetime(const PVR_RECORDING*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING& recording, int count)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastplayedposition)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  int GetRecordingLastPlayedPosition(const PVR_RECORDING& recording)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY edl[], int* size)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR GetRecordingSize(const PVR_RECORDING* recording, int64_t* sizeInBytes)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR GetTimerTypes(PVR_TIMER_TYPE types[], int* size) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  int GetTimersAmount(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR GetTimers(ADDON_HANDLE handle) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR AddTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR DeleteTimer(const PVR_TIMER& timer, bool bForceDelete)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR UpdateTimer(const PVR_TIMER& timer) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
/* PVR stream properties handling */
 | 
			
		||||
PVR_ERROR GetStreamReadChunkSize(int* chunksize) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetChannelStreamProperties(const PVR_CHANNEL*, PVR_NAMED_VALUE*, unsigned int*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetRecordingStreamProperties(const PVR_RECORDING*, PVR_NAMED_VALUE*, unsigned int*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetEPGTagStreamProperties(const EPG_TAG*, PVR_NAMED_VALUE*, unsigned int*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetEPGTagEdl(const EPG_TAG* epgTag, PVR_EDL_ENTRY edl[], int *size) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  /* PVR stream properties handling */
 | 
			
		||||
  PVR_ERROR GetStreamReadChunkSize(int* chunksize) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR GetChannelStreamProperties(const PVR_CHANNEL*, PVR_NAMED_VALUE*, unsigned int*)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR GetRecordingStreamProperties(const PVR_RECORDING*, PVR_NAMED_VALUE*, unsigned int*)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR GetEPGTagStreamProperties(const EPG_TAG*, PVR_NAMED_VALUE*, unsigned int*)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR GetEPGTagEdl(const EPG_TAG* epgTag, PVR_EDL_ENTRY edl[], int* size)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
/* PVR stream handling */
 | 
			
		||||
/* entirely unused, as we use standard RTSP+TS mux, which can be handlded by
 | 
			
		||||
  /* PVR stream handling */
 | 
			
		||||
  /* entirely unused, as we use standard RTSP+TS mux, which can be handlded by
 | 
			
		||||
 * Kodi core */
 | 
			
		||||
bool OpenLiveStream(const PVR_CHANNEL& channel) {
 | 
			
		||||
	return rtsp_open(data->getName(channel.iUniqueId), data->getUrl(channel.iUniqueId));
 | 
			
		||||
}
 | 
			
		||||
  bool OpenLiveStream(const PVR_CHANNEL& channel)
 | 
			
		||||
  {
 | 
			
		||||
    return rtsp_open(data->GetName(channel.iUniqueId), data->GetUrl(channel.iUniqueId));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
int ReadLiveStream(unsigned char* pBuffer, unsigned int iBufferSize) {
 | 
			
		||||
  int ReadLiveStream(unsigned char* pBuffer, unsigned int iBufferSize)
 | 
			
		||||
  {
 | 
			
		||||
    return rtsp_read(pBuffer, iBufferSize);
 | 
			
		||||
}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
void CloseLiveStream(void) {
 | 
			
		||||
	rtsp_close();
 | 
			
		||||
}
 | 
			
		||||
  void CloseLiveStream(void) { rtsp_close(); }
 | 
			
		||||
 | 
			
		||||
long long SeekLiveStream(long long iPosition, int iWhence) { return -1; }
 | 
			
		||||
long long LengthLiveStream(void) { return -1; }
 | 
			
		||||
bool IsRealTimeStream(void) { return true; }
 | 
			
		||||
  long long SeekLiveStream(long long iPosition, int iWhence) { return -1; }
 | 
			
		||||
  long long LengthLiveStream(void) { return -1; }
 | 
			
		||||
  bool IsRealTimeStream(void) { return true; }
 | 
			
		||||
 | 
			
		||||
PVR_ERROR GetSignalStatus(int channelUid, PVR_SIGNAL_STATUS* signalStatus) {
 | 
			
		||||
  PVR_ERROR GetSignalStatus(int channelUid, PVR_SIGNAL_STATUS* signalStatus)
 | 
			
		||||
  {
 | 
			
		||||
    memset(signalStatus, 0, sizeof(PVR_SIGNAL_STATUS));
 | 
			
		||||
    rtsp_fill_signal_status(signalStatus);
 | 
			
		||||
    return PVR_ERROR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PVR_ERROR GetStreamTimes(PVR_STREAM_TIMES *times) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES* pProperties) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
PVR_ERROR GetDescrambleInfo(int, PVR_DESCRAMBLE_INFO*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
/* Recording stream handling */
 | 
			
		||||
bool OpenRecordedStream(const PVR_RECORDING& recording) { return false; }
 | 
			
		||||
void CloseRecordedStream(void) {}
 | 
			
		||||
int ReadRecordedStream(unsigned char* pBuffer, unsigned int iBufferSize) { return -1; }
 | 
			
		||||
long long SeekRecordedStream(long long iPosition, int iWhence) { return -1; }
 | 
			
		||||
long long LengthRecordedStream(void) { return -1; }
 | 
			
		||||
 | 
			
		||||
/* PVR demuxer */
 | 
			
		||||
/* entirey unused, as we use TS */
 | 
			
		||||
void DemuxReset(void) {}
 | 
			
		||||
void DemuxAbort(void) {}
 | 
			
		||||
void DemuxFlush(void) {}
 | 
			
		||||
DemuxPacket* DemuxRead(void) { return NULL; }
 | 
			
		||||
void FillBuffer(bool mode) {}
 | 
			
		||||
 | 
			
		||||
/* Various helper functions */
 | 
			
		||||
bool CanPauseStream() { return false; }
 | 
			
		||||
bool CanSeekStream() { return false; }
 | 
			
		||||
 | 
			
		||||
/* Callbacks */
 | 
			
		||||
void PauseStream(bool bPaused) {}
 | 
			
		||||
bool SeekTime(double time, bool backwards, double *startpts) { return false; }
 | 
			
		||||
void SetSpeed(int speed) {}
 | 
			
		||||
PVR_ERROR SetEPGTimeFrame(int) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
const char* GetBackendHostname()
 | 
			
		||||
{
 | 
			
		||||
	return octonetAddress.c_str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  PVR_ERROR GetStreamTimes(PVR_STREAM_TIMES* times) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
  PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES* pProperties)
 | 
			
		||||
  {
 | 
			
		||||
    return PVR_ERROR_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
  PVR_ERROR GetDescrambleInfo(int, PVR_DESCRAMBLE_INFO*) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
  /* Recording stream handling */
 | 
			
		||||
  bool OpenRecordedStream(const PVR_RECORDING& recording) { return false; }
 | 
			
		||||
  void CloseRecordedStream(void) {}
 | 
			
		||||
  int ReadRecordedStream(unsigned char* pBuffer, unsigned int iBufferSize) { return -1; }
 | 
			
		||||
  long long SeekRecordedStream(long long iPosition, int iWhence) { return -1; }
 | 
			
		||||
  long long LengthRecordedStream(void) { return -1; }
 | 
			
		||||
 | 
			
		||||
  /* PVR demuxer */
 | 
			
		||||
  /* entirey unused, as we use TS */
 | 
			
		||||
  void DemuxReset(void) {}
 | 
			
		||||
  void DemuxAbort(void) {}
 | 
			
		||||
  void DemuxFlush(void) {}
 | 
			
		||||
  DemuxPacket* DemuxRead(void) { return nullptr; }
 | 
			
		||||
  void FillBuffer(bool mode) {}
 | 
			
		||||
 | 
			
		||||
  /* Various helper functions */
 | 
			
		||||
  bool CanPauseStream() { return false; }
 | 
			
		||||
  bool CanSeekStream() { return false; }
 | 
			
		||||
 | 
			
		||||
  /* Callbacks */
 | 
			
		||||
  void PauseStream(bool bPaused) {}
 | 
			
		||||
  bool SeekTime(double time, bool backwards, double* startpts) { return false; }
 | 
			
		||||
  void SetSpeed(int speed) {}
 | 
			
		||||
  PVR_ERROR SetEPGTimeFrame(int) { return PVR_ERROR_NOT_IMPLEMENTED; }
 | 
			
		||||
 | 
			
		||||
  const char* GetBackendHostname() { return octonetAddress.c_str(); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@
 | 
			
		||||
#define __func__ __FUNCTION__
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern ADDON::CHelper_libXBMC_addon *libKodi;
 | 
			
		||||
extern CHelper_libXBMC_pvr *pvr;
 | 
			
		||||
extern ADDON::CHelper_libXBMC_addon* libKodi;
 | 
			
		||||
extern CHelper_libXBMC_pvr* pvr;
 | 
			
		||||
 | 
			
		||||
/* IP or hostname of the octonet to be connected to */
 | 
			
		||||
extern std::string octonetAddress;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Copyright (C) 2005-2020 Team Kodi
 | 
			
		||||
 *  https://kodi.tv
 | 
			
		||||
 *
 | 
			
		||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 *  See LICENSE.md for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rtsp_client.hpp"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cctype>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
 | 
			
		||||
#include "Socket.h"
 | 
			
		||||
#include "client.h"
 | 
			
		||||
#include <p8-platform/util/util.h>
 | 
			
		||||
#include <kodi/libXBMC_addon.h>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cctype>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <kodi/libXBMC_addon.h>
 | 
			
		||||
#include <p8-platform/util/util.h>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined(_WIN64)
 | 
			
		||||
#define strtok_r strtok_s
 | 
			
		||||
#define strncasecmp _strnicmp
 | 
			
		||||
 | 
			
		||||
int vasprintf(char **sptr, char *fmt, va_list argv) {
 | 
			
		||||
	int wanted = vsnprintf(*sptr = NULL, 0, fmt, argv);
 | 
			
		||||
	if((wanted < 0) || ((*sptr = (char *)malloc(1 + wanted)) == NULL))
 | 
			
		||||
int vasprintf(char** sptr, char* fmt, va_list argv)
 | 
			
		||||
{
 | 
			
		||||
  int wanted = vsnprintf(*sptr = nullptr, 0, fmt, argv);
 | 
			
		||||
  if ((wanted < 0) || ((*sptr = (char*)malloc(1 + wanted)) == nullptr))
 | 
			
		||||
    return -1;
 | 
			
		||||
  return vsprintf(*sptr, fmt, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int asprintf(char **sptr, char *fmt, ...) {
 | 
			
		||||
int asprintf(char** sptr, char* fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  int retval;
 | 
			
		||||
  va_list argv;
 | 
			
		||||
  va_start(argv, fmt);
 | 
			
		||||
@@ -43,7 +55,8 @@ using namespace std;
 | 
			
		||||
using namespace ADDON;
 | 
			
		||||
using namespace OCTO;
 | 
			
		||||
 | 
			
		||||
enum rtsp_state {
 | 
			
		||||
enum rtsp_state
 | 
			
		||||
{
 | 
			
		||||
  RTSP_IDLE,
 | 
			
		||||
  RTSP_DESCRIBE,
 | 
			
		||||
  RTSP_SETUP,
 | 
			
		||||
@@ -51,13 +64,15 @@ enum rtsp_state {
 | 
			
		||||
  RTSP_RUNNING
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum rtsp_result {
 | 
			
		||||
enum rtsp_result
 | 
			
		||||
{
 | 
			
		||||
  RTSP_RESULT_OK = 200,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rtsp_client {
 | 
			
		||||
	char *content_base;
 | 
			
		||||
	char *control;
 | 
			
		||||
struct rtsp_client
 | 
			
		||||
{
 | 
			
		||||
  char* content_base;
 | 
			
		||||
  char* control;
 | 
			
		||||
  char session_id[64];
 | 
			
		||||
  uint16_t stream_id;
 | 
			
		||||
  int keepalive_interval;
 | 
			
		||||
@@ -80,14 +95,16 @@ struct rtsp_client {
 | 
			
		||||
  int quality;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct url {
 | 
			
		||||
struct url
 | 
			
		||||
{
 | 
			
		||||
  string protocol;
 | 
			
		||||
  string host;
 | 
			
		||||
  int port;
 | 
			
		||||
  string path;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rtcp_app {
 | 
			
		||||
struct rtcp_app
 | 
			
		||||
{
 | 
			
		||||
  uint8_t subtype;
 | 
			
		||||
  uint8_t pt;
 | 
			
		||||
  uint16_t len;
 | 
			
		||||
@@ -97,9 +114,10 @@ struct rtcp_app {
 | 
			
		||||
  uint16_t string_len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static rtsp_client *rtsp = NULL;
 | 
			
		||||
static rtsp_client* rtsp = nullptr;
 | 
			
		||||
 | 
			
		||||
static url parse_url(const std::string& str) {
 | 
			
		||||
static url parse_url(const std::string& str)
 | 
			
		||||
{
 | 
			
		||||
  static const string prot_end = "://";
 | 
			
		||||
  static const string host_end = "/";
 | 
			
		||||
  url result;
 | 
			
		||||
@@ -125,22 +143,27 @@ static url parse_url(const std::string& str) {
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void split_string(const string& s, char delim, vector<string>& elems) {
 | 
			
		||||
void split_string(const string& s, char delim, vector<string>& elems)
 | 
			
		||||
{
 | 
			
		||||
  stringstream ss;
 | 
			
		||||
  ss.str(s);
 | 
			
		||||
 | 
			
		||||
  string item;
 | 
			
		||||
	while(getline(ss, item, delim)) {
 | 
			
		||||
  while (getline(ss, item, delim))
 | 
			
		||||
  {
 | 
			
		||||
    elems.push_back(item);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int tcp_sock_read_line(string &line) {
 | 
			
		||||
static int tcp_sock_read_line(string& line)
 | 
			
		||||
{
 | 
			
		||||
  static string buf;
 | 
			
		||||
 | 
			
		||||
	while(true) {
 | 
			
		||||
  while (true)
 | 
			
		||||
  {
 | 
			
		||||
    string::size_type pos = buf.find("\r\n");
 | 
			
		||||
		if(pos != string::npos) {
 | 
			
		||||
    if (pos != string::npos)
 | 
			
		||||
    {
 | 
			
		||||
      line = buf.substr(0, pos);
 | 
			
		||||
      buf.erase(0, pos + 2);
 | 
			
		||||
      return 0;
 | 
			
		||||
@@ -148,7 +171,8 @@ static int tcp_sock_read_line(string &line) {
 | 
			
		||||
 | 
			
		||||
    char tmp_buf[2048];
 | 
			
		||||
    int size = rtsp->tcp_sock.receive(tmp_buf, sizeof(tmp_buf), 1);
 | 
			
		||||
		if(size <= 0) {
 | 
			
		||||
    if (size <= 0)
 | 
			
		||||
    {
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -167,17 +191,20 @@ static string compose_url(const url& u)
 | 
			
		||||
  return res.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void parse_session(char *request_line, char *session, unsigned max, int *timeout) {
 | 
			
		||||
	char *state;
 | 
			
		||||
	char *tok;
 | 
			
		||||
static void parse_session(char* request_line, char* session, unsigned max, int* timeout)
 | 
			
		||||
{
 | 
			
		||||
  char* state;
 | 
			
		||||
  char* tok;
 | 
			
		||||
 | 
			
		||||
  tok = strtok_r(request_line, ";", &state);
 | 
			
		||||
	if (tok == NULL)
 | 
			
		||||
  if (tok == nullptr)
 | 
			
		||||
    return;
 | 
			
		||||
  strncpy(session, tok, min(strlen(tok), (size_t)(max - 1)));
 | 
			
		||||
 | 
			
		||||
	while ((tok = strtok_r(NULL, ";", &state)) != NULL) {
 | 
			
		||||
		if (strncmp(tok, "timeout=", 8) == 0) {
 | 
			
		||||
  while ((tok = strtok_r(nullptr, ";", &state)) != nullptr)
 | 
			
		||||
  {
 | 
			
		||||
    if (strncmp(tok, "timeout=", 8) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      *timeout = atoi(tok + 8);
 | 
			
		||||
      if (*timeout > 5)
 | 
			
		||||
        *timeout -= KEEPALIVE_MARGIN;
 | 
			
		||||
@@ -187,7 +214,7 @@ static void parse_session(char *request_line, char *session, unsigned max, int *
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_port(char *str, uint16_t *port)
 | 
			
		||||
static int parse_port(char* str, uint16_t* port)
 | 
			
		||||
{
 | 
			
		||||
  int p = atoi(str);
 | 
			
		||||
  if (p < 0 || p > UINT16_MAX)
 | 
			
		||||
@@ -198,29 +225,34 @@ static int parse_port(char *str, uint16_t *port)
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_transport(char *request_line) {
 | 
			
		||||
	char *state;
 | 
			
		||||
	char *tok;
 | 
			
		||||
static int parse_transport(char* request_line)
 | 
			
		||||
{
 | 
			
		||||
  char* state;
 | 
			
		||||
  char* tok;
 | 
			
		||||
  int err;
 | 
			
		||||
 | 
			
		||||
  tok = strtok_r(request_line, ";", &state);
 | 
			
		||||
	if (tok == NULL || strncmp(tok, "RTP/AVP", 7) != 0)
 | 
			
		||||
  if (tok == nullptr || strncmp(tok, "RTP/AVP", 7) != 0)
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
	tok = strtok_r(NULL, ";", &state);
 | 
			
		||||
	if (tok == NULL || strncmp(tok, "multicast", 9) != 0)
 | 
			
		||||
  tok = strtok_r(nullptr, ";", &state);
 | 
			
		||||
  if (tok == nullptr || strncmp(tok, "multicast", 9) != 0)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
	while ((tok = strtok_r(NULL, ";", &state)) != NULL) {
 | 
			
		||||
		if (strncmp(tok, "destination=", 12) == 0) {
 | 
			
		||||
  while ((tok = strtok_r(nullptr, ";", &state)) != nullptr)
 | 
			
		||||
  {
 | 
			
		||||
    if (strncmp(tok, "destination=", 12) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      strncpy(rtsp->udp_address, tok + 12, min(strlen(tok + 12), (size_t)(UDP_ADDRESS_LEN - 1)));
 | 
			
		||||
		} else if (strncmp(tok, "port=", 5) == 0) {
 | 
			
		||||
    }
 | 
			
		||||
    else if (strncmp(tok, "port=", 5) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      char port[6];
 | 
			
		||||
			char *end;
 | 
			
		||||
      char* end;
 | 
			
		||||
 | 
			
		||||
      memset(port, 0x00, 6);
 | 
			
		||||
      strncpy(port, tok + 5, min(strlen(tok + 5), (size_t)5));
 | 
			
		||||
			if ((end = strstr(port, "-")) != NULL)
 | 
			
		||||
      if ((end = strstr(port, "-")) != nullptr)
 | 
			
		||||
        *end = '\0';
 | 
			
		||||
      err = parse_port(port, &rtsp->udp_port);
 | 
			
		||||
      if (err)
 | 
			
		||||
@@ -231,8 +263,11 @@ static int parse_transport(char *request_line) {
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define skip_whitespace(x) while(*x == ' ') x++
 | 
			
		||||
static enum rtsp_result rtsp_handle() {
 | 
			
		||||
#define skip_whitespace(x) \
 | 
			
		||||
  while (*x == ' ') \
 | 
			
		||||
  x++
 | 
			
		||||
static enum rtsp_result rtsp_handle()
 | 
			
		||||
{
 | 
			
		||||
  uint8_t buffer[512];
 | 
			
		||||
  int rtsp_result = 0;
 | 
			
		||||
  bool have_header = false;
 | 
			
		||||
@@ -242,51 +277,66 @@ static enum rtsp_result rtsp_handle() {
 | 
			
		||||
  string in_str;
 | 
			
		||||
 | 
			
		||||
  /* Parse header */
 | 
			
		||||
	while (!have_header) {
 | 
			
		||||
  while (!have_header)
 | 
			
		||||
  {
 | 
			
		||||
    if (tcp_sock_read_line(in_str) < 0)
 | 
			
		||||
      break;
 | 
			
		||||
		in = const_cast<char *>(in_str.c_str());
 | 
			
		||||
    in = const_cast<char*>(in_str.c_str());
 | 
			
		||||
 | 
			
		||||
		if (strncmp(in, "RTSP/1.0 ", 9) == 0) {
 | 
			
		||||
    if (strncmp(in, "RTSP/1.0 ", 9) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      rtsp_result = atoi(in + 9);
 | 
			
		||||
		} else if (strncmp(in, "Content-Base:", 13) == 0) {
 | 
			
		||||
    }
 | 
			
		||||
    else if (strncmp(in, "Content-Base:", 13) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      free(rtsp->content_base);
 | 
			
		||||
 | 
			
		||||
      val = in + 13;
 | 
			
		||||
      skip_whitespace(val);
 | 
			
		||||
 | 
			
		||||
      rtsp->content_base = strdup(val);
 | 
			
		||||
		} else if (strncmp(in, "Content-Length:", 15) == 0) {
 | 
			
		||||
    }
 | 
			
		||||
    else if (strncmp(in, "Content-Length:", 15) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      val = in + 16;
 | 
			
		||||
      skip_whitespace(val);
 | 
			
		||||
 | 
			
		||||
      content_length = atoi(val);
 | 
			
		||||
		} else if (strncmp("Session:", in, 8) == 0) {
 | 
			
		||||
    }
 | 
			
		||||
    else if (strncmp("Session:", in, 8) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      val = in + 8;
 | 
			
		||||
      skip_whitespace(val);
 | 
			
		||||
 | 
			
		||||
      parse_session(val, rtsp->session_id, 64, &rtsp->keepalive_interval);
 | 
			
		||||
		} else if (strncmp("Transport:", in, 10) == 0) {
 | 
			
		||||
    }
 | 
			
		||||
    else if (strncmp("Transport:", in, 10) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      val = in + 10;
 | 
			
		||||
      skip_whitespace(val);
 | 
			
		||||
 | 
			
		||||
			if (parse_transport(val) != 0) {
 | 
			
		||||
      if (parse_transport(val) != 0)
 | 
			
		||||
      {
 | 
			
		||||
        rtsp_result = -1;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
		} else if (strncmp("com.ses.streamID:", in, 17) == 0) {
 | 
			
		||||
    }
 | 
			
		||||
    else if (strncmp("com.ses.streamID:", in, 17) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      val = in + 17;
 | 
			
		||||
      skip_whitespace(val);
 | 
			
		||||
 | 
			
		||||
      rtsp->stream_id = atoi(val);
 | 
			
		||||
		} else if (in[0] == '\0') {
 | 
			
		||||
    }
 | 
			
		||||
    else if (in[0] == '\0')
 | 
			
		||||
    {
 | 
			
		||||
      have_header = true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Discard further content */
 | 
			
		||||
	while (content_length > 0 &&
 | 
			
		||||
			(read = rtsp->tcp_sock.receive((char*)buffer, sizeof(buffer), min(sizeof(buffer), content_length))))
 | 
			
		||||
  while (content_length > 0 && (read = rtsp->tcp_sock.receive((char*)buffer, sizeof(buffer),
 | 
			
		||||
                                                              min(sizeof(buffer), content_length))))
 | 
			
		||||
    content_length -= read;
 | 
			
		||||
 | 
			
		||||
  return (enum rtsp_result)rtsp_result;
 | 
			
		||||
@@ -295,14 +345,14 @@ static enum rtsp_result rtsp_handle() {
 | 
			
		||||
bool rtsp_open(const string& name, const string& url_str)
 | 
			
		||||
{
 | 
			
		||||
  string setup_url_str;
 | 
			
		||||
	const char *psz_setup_url;
 | 
			
		||||
  const char* psz_setup_url;
 | 
			
		||||
  stringstream setup_ss;
 | 
			
		||||
  stringstream play_ss;
 | 
			
		||||
  url setup_url;
 | 
			
		||||
 | 
			
		||||
  rtsp_close();
 | 
			
		||||
  rtsp = new rtsp_client();
 | 
			
		||||
	if (rtsp == NULL)
 | 
			
		||||
  if (rtsp == nullptr)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  rtsp->name = name;
 | 
			
		||||
@@ -314,16 +364,17 @@ bool rtsp_open(const string& name, const string& url_str)
 | 
			
		||||
  url dst = parse_url(url_str);
 | 
			
		||||
  libKodi->Log(LOG_DEBUG, "connect to host '%s'", dst.host.c_str());
 | 
			
		||||
 | 
			
		||||
	if(!rtsp->tcp_sock.connect(dst.host, dst.port)) {
 | 
			
		||||
  if (!rtsp->tcp_sock.connect(dst.host, dst.port))
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Failed to connect to RTSP server %s:%d", dst.host.c_str(), dst.port);
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: tcp keep alive?
 | 
			
		||||
 | 
			
		||||
	if (asprintf(&rtsp->content_base, "rtsp://%s:%d/", dst.host.c_str(),
 | 
			
		||||
				dst.port) < 0) {
 | 
			
		||||
		rtsp->content_base = NULL;
 | 
			
		||||
  if (asprintf(&rtsp->content_base, "rtsp://%s:%d/", dst.host.c_str(), dst.port) < 0)
 | 
			
		||||
  {
 | 
			
		||||
    rtsp->content_base = nullptr;
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -333,7 +384,8 @@ bool rtsp_open(const string& name, const string& url_str)
 | 
			
		||||
  setup_url = dst;
 | 
			
		||||
 | 
			
		||||
  // reverse the satip protocol trick, as SAT>IP believes to be RTSP
 | 
			
		||||
	if (!strncasecmp(setup_url.protocol.c_str(), "satip", 5)) {
 | 
			
		||||
  if (!strncasecmp(setup_url.protocol.c_str(), "satip", 5))
 | 
			
		||||
  {
 | 
			
		||||
    setup_url.protocol = "rtsp";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -343,22 +395,26 @@ bool rtsp_open(const string& name, const string& url_str)
 | 
			
		||||
  // TODO: Find available port
 | 
			
		||||
  rtsp->udp_sock = Socket(af_inet, pf_inet, sock_dgram, udp);
 | 
			
		||||
  rtsp->udp_port = 6785;
 | 
			
		||||
	if(!rtsp->udp_sock.bind(rtsp->udp_port)) {
 | 
			
		||||
  if (!rtsp->udp_sock.bind(rtsp->udp_port))
 | 
			
		||||
  {
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
	setup_ss << "SETUP " << setup_url_str<< " RTSP/1.0\r\n";
 | 
			
		||||
  setup_ss << "SETUP " << setup_url_str << " RTSP/1.0\r\n";
 | 
			
		||||
  setup_ss << "CSeq: " << rtsp->cseq++ << "\r\n";
 | 
			
		||||
	setup_ss << "Transport: RTP/AVP;unicast;client_port=" << rtsp->udp_port << "-" << (rtsp->udp_port + 1) << "\r\n\r\n";
 | 
			
		||||
  setup_ss << "Transport: RTP/AVP;unicast;client_port=" << rtsp->udp_port << "-"
 | 
			
		||||
           << (rtsp->udp_port + 1) << "\r\n\r\n";
 | 
			
		||||
  rtsp->tcp_sock.send(setup_ss.str());
 | 
			
		||||
 | 
			
		||||
	if (rtsp_handle() != RTSP_RESULT_OK) {
 | 
			
		||||
  if (rtsp_handle() != RTSP_RESULT_OK)
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Failed to setup RTSP session");
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
	if (asprintf(&rtsp->control, "%sstream=%d", rtsp->content_base, rtsp->stream_id) < 0) {
 | 
			
		||||
		rtsp->control = NULL;
 | 
			
		||||
  if (asprintf(&rtsp->control, "%sstream=%d", rtsp->content_base, rtsp->stream_id) < 0)
 | 
			
		||||
  {
 | 
			
		||||
    rtsp->control = nullptr;
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -367,16 +423,19 @@ bool rtsp_open(const string& name, const string& url_str)
 | 
			
		||||
  play_ss << "Session: " << rtsp->session_id << "\r\n\r\n";
 | 
			
		||||
  rtsp->tcp_sock.send(play_ss.str());
 | 
			
		||||
 | 
			
		||||
	if (rtsp_handle() != RTSP_RESULT_OK) {
 | 
			
		||||
  if (rtsp_handle() != RTSP_RESULT_OK)
 | 
			
		||||
  {
 | 
			
		||||
    libKodi->Log(LOG_ERROR, "Failed to play RTSP session");
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  rtsp->rtcp_sock = Socket(af_inet, pf_inet, sock_dgram, udp);
 | 
			
		||||
	if(!rtsp->rtcp_sock.bind(rtsp->udp_port + 1)) {
 | 
			
		||||
  if (!rtsp->rtcp_sock.bind(rtsp->udp_port + 1))
 | 
			
		||||
  {
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
	if(!rtsp->rtcp_sock.set_non_blocking(true)) {
 | 
			
		||||
  if (!rtsp->rtcp_sock.set_non_blocking(true))
 | 
			
		||||
  {
 | 
			
		||||
    goto error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -387,13 +446,16 @@ error:
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void parse_rtcp(const char *buf, int size) {
 | 
			
		||||
static void parse_rtcp(const char* buf, int size)
 | 
			
		||||
{
 | 
			
		||||
  int offset = 0;
 | 
			
		||||
	while(size > 4) {
 | 
			
		||||
		const rtcp_app *app = reinterpret_cast<const rtcp_app *>(buf + offset);
 | 
			
		||||
  while (size > 4)
 | 
			
		||||
  {
 | 
			
		||||
    const rtcp_app* app = reinterpret_cast<const rtcp_app*>(buf + offset);
 | 
			
		||||
    uint16_t len = 4 * (ntohs(app->len) + 1);
 | 
			
		||||
 | 
			
		||||
		if((app->pt != 204) || (memcmp(app->name, "SES1", 4) != 0)) {
 | 
			
		||||
    if ((app->pt != 204) || (memcmp(app->name, "SES1", 4) != 0))
 | 
			
		||||
    {
 | 
			
		||||
      size -= len;
 | 
			
		||||
      offset += len;
 | 
			
		||||
      continue;
 | 
			
		||||
@@ -404,13 +466,15 @@ static void parse_rtcp(const char *buf, int size) {
 | 
			
		||||
 | 
			
		||||
    vector<string> elems;
 | 
			
		||||
    split_string(app_data, ';', elems);
 | 
			
		||||
		if(elems.size() != 4) {
 | 
			
		||||
    if (elems.size() != 4)
 | 
			
		||||
    {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vector<string> tuner;
 | 
			
		||||
    split_string(elems[2], ',', tuner);
 | 
			
		||||
		if(tuner.size() < 4) {
 | 
			
		||||
    if (tuner.size() < 4)
 | 
			
		||||
    {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -421,13 +485,14 @@ static void parse_rtcp(const char *buf, int size) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rtsp_read(void *buf, unsigned buf_size) {
 | 
			
		||||
int rtsp_read(void* buf, unsigned buf_size)
 | 
			
		||||
{
 | 
			
		||||
  sockaddr addr;
 | 
			
		||||
  socklen_t addr_len = sizeof(addr);
 | 
			
		||||
	int ret = rtsp->udp_sock.recvfrom((char *)buf, buf_size, (sockaddr *)&addr, &addr_len);
 | 
			
		||||
  int ret = rtsp->udp_sock.recvfrom((char*)buf, buf_size, (sockaddr*)&addr, &addr_len);
 | 
			
		||||
 | 
			
		||||
  char rtcp_buf[RTCP_BUFFER_SIZE];
 | 
			
		||||
	int rtcp_len = rtsp->rtcp_sock.recvfrom(rtcp_buf, RTCP_BUFFER_SIZE, (sockaddr *)&addr, &addr_len);
 | 
			
		||||
  int rtcp_len = rtsp->rtcp_sock.recvfrom(rtcp_buf, RTCP_BUFFER_SIZE, (sockaddr*)&addr, &addr_len);
 | 
			
		||||
  parse_rtcp(rtcp_buf, rtcp_len);
 | 
			
		||||
 | 
			
		||||
  // TODO: check ip
 | 
			
		||||
@@ -435,13 +500,16 @@ int rtsp_read(void *buf, unsigned buf_size) {
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rtsp_teardown() {
 | 
			
		||||
	if(!rtsp->tcp_sock.is_valid()) {
 | 
			
		||||
static void rtsp_teardown()
 | 
			
		||||
{
 | 
			
		||||
  if (!rtsp->tcp_sock.is_valid())
 | 
			
		||||
  {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
	if (rtsp->session_id[0] > 0) {
 | 
			
		||||
		char *msg;
 | 
			
		||||
  if (rtsp->session_id[0] > 0)
 | 
			
		||||
  {
 | 
			
		||||
    char* msg;
 | 
			
		||||
    int len;
 | 
			
		||||
    stringstream ss;
 | 
			
		||||
 | 
			
		||||
@@ -452,7 +520,8 @@ static void rtsp_teardown() {
 | 
			
		||||
    ss << "Session: " << rtsp->session_id << "\r\n\r\n";
 | 
			
		||||
    rtsp->tcp_sock.send(ss.str());
 | 
			
		||||
 | 
			
		||||
		if (rtsp_handle() != RTSP_RESULT_OK) {
 | 
			
		||||
    if (rtsp_handle() != RTSP_RESULT_OK)
 | 
			
		||||
    {
 | 
			
		||||
      libKodi->Log(LOG_ERROR, "Failed to teardown RTSP session");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -461,18 +530,21 @@ static void rtsp_teardown() {
 | 
			
		||||
 | 
			
		||||
void rtsp_close()
 | 
			
		||||
{
 | 
			
		||||
	if(rtsp) {
 | 
			
		||||
  if (rtsp)
 | 
			
		||||
  {
 | 
			
		||||
    rtsp_teardown();
 | 
			
		||||
    rtsp->tcp_sock.close();
 | 
			
		||||
    rtsp->udp_sock.close();
 | 
			
		||||
    rtsp->rtcp_sock.close();
 | 
			
		||||
    delete rtsp;
 | 
			
		||||
		rtsp = NULL;
 | 
			
		||||
    rtsp = nullptr;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rtsp_fill_signal_status(PVR_SIGNAL_STATUS* signal_status) {
 | 
			
		||||
	if(rtsp) {
 | 
			
		||||
void rtsp_fill_signal_status(PVR_SIGNAL_STATUS* signal_status)
 | 
			
		||||
{
 | 
			
		||||
  if (rtsp)
 | 
			
		||||
  {
 | 
			
		||||
    strncpy(signal_status->strServiceName, rtsp->name.c_str(), PVR_ADDON_NAME_STRING_LENGTH - 1);
 | 
			
		||||
    signal_status->iSNR = 0x1111 * rtsp->quality;
 | 
			
		||||
    signal_status->iSignal = 0x101 * rtsp->level;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,18 @@
 | 
			
		||||
#ifndef _RTSP_CLIENT_HPP_
 | 
			
		||||
#define _RTSP_CLIENT_HPP_
 | 
			
		||||
/*
 | 
			
		||||
 *  Copyright (C) 2005-2020 Team Kodi
 | 
			
		||||
 *  https://kodi.tv
 | 
			
		||||
 *
 | 
			
		||||
 *  SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 *  See LICENSE.md for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <kodi/xbmc_pvr_types.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
bool rtsp_open(const std::string& name, const std::string& url_str);
 | 
			
		||||
void rtsp_close();
 | 
			
		||||
int rtsp_read(void *buf, unsigned buf_size);
 | 
			
		||||
int rtsp_read(void* buf, unsigned buf_size);
 | 
			
		||||
void rtsp_fill_signal_status(PVR_SIGNAL_STATUS* signal_status);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user