Fully implemented DTSC pull support

This commit is contained in:
Erik Zandvliet 2016-03-15 11:29:01 +01:00 committed by Thulinma
parent 668560ff05
commit dda0ea669c
27 changed files with 930 additions and 272 deletions

View file

@ -264,6 +264,10 @@ bool Util::Config::parseArgs(int & argc, char ** & argv) {
return true;
}
bool Util::Config::hasOption(const std::string & optname) {
return vals.isMember(optname);
}
/// Returns a reference to the current value of an option or default if none was set.
/// If the option does not exist, this exits the application with a return code of 37.
JSON::Value & Util::Config::getOption(std::string optname, bool asArray) {

View file

@ -30,6 +30,7 @@ namespace Util {
void addOption(std::string optname, JSON::Value option);
void printHelp(std::ostream & output);
bool parseArgs(int & argc, char ** & argv);
bool hasOption(const std::string & optname);
JSON::Value & getOption(std::string optname, bool asArray = false);
std::string getString(std::string optname);
long long int getInteger(std::string optname);

View file

@ -109,6 +109,7 @@ namespace DTSC {
void operator = (const Packet & rhs);
operator bool() const;
packType getVersion() const;
void reInit(Socket::Connection & src);
void reInit(const char * data_, unsigned int len, bool noCopy = false);
void genericFill(long long packTime, long long packOffset, long long packTrack, const char * packData, long long packDataSize, long long packBytePos, bool isKeyframe);
void getString(const char * identifier, char *& result, unsigned int & len) const;
@ -354,8 +355,8 @@ namespace DTSC {
void update(long long packTime, long long packOffset, long long packTrack, long long packDataSize, long long packBytePos, bool isKeyframe, long long packSendSize = 0, unsigned long segment_size = 5000);
LTS*/
void update(long long packTime, long long packOffset, long long packTrack, long long packDataSize, long long packBytePos, bool isKeyframe, long long packSendSize = 0, unsigned long segment_size = 5000, const char * iVec = 0);
unsigned int getSendLen(bool skipDynamic = false);
void send(Socket::Connection & conn, bool skipDynamic = false);
unsigned int getSendLen(bool skipDynamic = false, std::set<unsigned long> selectedTracks = std::set<unsigned long>());
void send(Socket::Connection & conn, bool skipDynamic = false, std::set<unsigned long> selectedTracks = std::set<unsigned long>());
void writeTo(char * p);
JSON::Value toJSON();
void reset();

View file

@ -109,6 +109,32 @@ namespace DTSC {
}
}
void Packet::reInit(Socket::Connection & src) {
int sleepCount = 0;
null();
int toReceive = 0;
while (src.connected()){
if (!toReceive && src.Received().available(8)){
if (src.Received().copy(2) != "DT"){
INFO_MSG("Invalid DTSC Packet header encountered (%s)", src.Received().copy(4).c_str());
break;
}
toReceive = Bit::btohl(src.Received().copy(8).data() + 4);
}
if (toReceive && src.Received().available(toReceive + 8)){
std::string dataBuf = src.Received().remove(toReceive + 8);
reInit(dataBuf.data(), dataBuf.size());
return;
}
if(!src.spool()){
if (sleepCount++ > 5){
return;
}
Util::sleep(500);
}
}
}
///\brief Initializes a packet with new data
///\param data_ The new data for the packet
///\param len The length of the data pointed to by data_
@ -1530,7 +1556,7 @@ namespace DTSC {
} else if (type == "video") {
result += 48;
}
if (missedFrags) {
if (!skipDynamic && missedFrags) {
result += 23;
}
return result;
@ -1709,10 +1735,12 @@ namespace DTSC {
}
///\brief Determines the "packed" size of a meta object
unsigned int Meta::getSendLen(bool skipDynamic) {
unsigned int Meta::getSendLen(bool skipDynamic, std::set<unsigned long> selectedTracks) {
unsigned int dataLen = 16 + (vod ? 14 : 0) + (live ? 15 : 0) + (merged ? 17 : 0) + (bufferWindow ? 24 : 0) + 21;
for (std::map<unsigned int, Track>::iterator it = tracks.begin(); it != tracks.end(); it++) {
dataLen += it->second.getSendLen(skipDynamic);
if (!selectedTracks.size() || selectedTracks.count(it->first)){
dataLen += it->second.getSendLen(skipDynamic);
}
}
return dataLen + 8; //add 8 bytes header
}
@ -1749,13 +1777,15 @@ namespace DTSC {
}
///\brief Writes a meta object to a socket
void Meta::send(Socket::Connection & conn, bool skipDynamic) {
int dataLen = getSendLen(skipDynamic) - 8; //strip 8 bytes header
void Meta::send(Socket::Connection & conn, bool skipDynamic, std::set<unsigned long> selectedTracks) {
int dataLen = getSendLen(skipDynamic, selectedTracks) - 8; //strip 8 bytes header
conn.SendNow(DTSC::Magic_Header, 4);
conn.SendNow(convertInt(dataLen), 4);
conn.SendNow("\340\000\006tracks\340", 10);
for (std::map<unsigned int, Track>::iterator it = tracks.begin(); it != tracks.end(); it++) {
it->second.send(conn, skipDynamic);
if (!selectedTracks.size() || selectedTracks.count(it->first)){
it->second.send(conn, skipDynamic);
}
}
conn.SendNow("\000\000\356", 3);//End tracks object
if (vod) {

View file

@ -1068,6 +1068,54 @@ namespace IPC {
///\brief The deconstructor
sharedClient::~sharedClient() {
mySemaphore.close();
}
bool sharedClient::isSingleEntry() {
semaphore tmpSem(baseName.c_str(), O_RDWR);
if (!tmpSem) {
HIGH_MSG("Creating semaphore %s failed: %s, assuming we're alone", baseName.c_str(), strerror(errno));
return true;
}
//Empty is used to compare for emptyness. This is not needed when the page uses a counter
char * empty = 0;
if (!hasCounter) {
empty = (char *)malloc(payLen * sizeof(char));
if (!empty) {
HIGH_MSG("Failed to allocate %u bytes for empty payload, assuming we're not alone", payLen);
return false;
}
memset(empty, 0, payLen);
}
bool result = true;
{
semGuard tmpGuard(&tmpSem);
for (char i = 'A'; i <= 'Z'; i++) {
sharedPage tmpPage(baseName.substr(1) + i, (4096 << (i - 'A')), false, false);
if (!tmpPage.mapped) {
break;
}
int offset = 0;
while (offset + payLen + (hasCounter ? 1 : 0) <= tmpPage.len) {
//Skip our own entry
if (tmpPage.name == myPage.name && offset == offsetOnPage){
offset += payLen + (hasCounter ? 1 : 0);
continue;
}
if (!((hasCounter && tmpPage.mapped[offset] == 0) || (!hasCounter && !memcmp(tmpPage.mapped + offset, empty, payLen)))) {
result = false;
break;
}
offset += payLen + (hasCounter ? 1 : 0);
}
}
}
if (empty) {
free(empty);
}
return result;
}
///\brief Writes data to the shared data
@ -1113,6 +1161,16 @@ namespace IPC {
}
return (myPage.mapped + offsetOnPage + (hasCounter ? 1 : 0));
}
int sharedClient::getCounter() {
if (!hasCounter){
return -1;
}
if (!myPage.mapped) {
return 0;
}
return *(myPage.mapped + offsetOnPage);
}
userConnection::userConnection(char * _data) {
data = _data;

View file

@ -60,7 +60,7 @@ namespace IPC {
class semaphore {
public:
semaphore();
semaphore(const char * name, int oflag, mode_t mode, unsigned int value);
semaphore(const char * name, int oflag, mode_t mode = 0, unsigned int value = 0);
~semaphore();
operator bool() const;
void open(const char * name, int oflag, mode_t mode = 0, unsigned int value = 0);
@ -220,6 +220,8 @@ namespace IPC {
void finish();
void keepAlive();
char * getData();
int getCounter();
bool isSingleEntry();
private:
///\brief The basename of the shared pages.
std::string baseName;

View file

@ -204,6 +204,7 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
//check in curConf for capabilities-inputs-<naam>-priority/source_match
std::string player_bin;
bool pullMode = false;
bool selected = false;
long long int curPrio = -1;
DTSC::Scan inputs = config.getMember("capabilities").getMember("inputs");
@ -224,6 +225,20 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
curPrio = input.getMember("priority").asInt();
selected = true;
}
if (input.hasMember("stream_match")){
source = input.getMember("stream_match").asString();
front = source.substr(0,source.find('*'));
back = source.substr(source.find('*')+1);
DEBUG_MSG(DLVL_MEDIUM, "Checking input %s: %s (%s)", inputs.getIndiceName(i).c_str(), input.getMember("name").asString().c_str(), source.c_str());
if (filename.substr(0,front.size()) == front && filename.substr(filename.size()-back.size()) == back){
player_bin = Util::getMyPath() + "MistIn" + input.getMember("name").asString();
curPrio = input.getMember("priority").asInt();
pullMode = true;
selected = true;
}
}
}
}
@ -261,9 +276,16 @@ bool Util::startInput(std::string streamname, std::string filename, bool forkFir
//finally, unlock the config semaphore
configLock.post();
DEBUG_MSG(DLVL_MEDIUM, "Starting %s -s %s %s", player_bin.c_str(), streamname.c_str(), filename.c_str());
if (pullMode){
DEBUG_MSG(DLVL_MEDIUM, "Starting %s -p -s %s %s", player_bin.c_str(), streamname.c_str(), filename.c_str());
}else{
DEBUG_MSG(DLVL_MEDIUM, "Starting %s -s %s %s", player_bin.c_str(), streamname.c_str(), filename.c_str());
}
char * argv[30] = {(char *)player_bin.c_str(), (char *)"-s", (char *)streamname.c_str(), (char *)filename.c_str()};
int argNum = 3;
if (pullMode){
argv[++argNum] = (char*)"--pull";
}
std::string debugLvl;
if (Util::Config::printDebugLevel != DEBUG && !str_args.count("--debug")){
debugLvl = JSON::Value((long long)Util::Config::printDebugLevel).asString();

40
lib/util.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "util.h"
#include <iostream>
namespace Util {
bool stringScan(const std::string & src, const std::string & pattern, std::deque<std::string> & result){
result.clear();
std::deque<size_t> positions;
size_t pos = pattern.find("%", 0);
while (pos != std::string::npos){
positions.push_back(pos);
pos = pattern.find("%", pos + 1);
}
if (positions.size() == 0){
return false;
}
size_t sourcePos = 0;
size_t patternPos = 0;
std::deque<size_t>::iterator posIter = positions.begin();
while (sourcePos != std::string::npos){
//Match first part of the string
if (pattern.substr(patternPos, *posIter - patternPos) != src.substr(sourcePos, *posIter - patternPos)){
break;
}
sourcePos += *posIter - patternPos;
std::deque<size_t>::iterator nxtIter = posIter + 1;
if (nxtIter != positions.end()){
patternPos = *posIter+2;
size_t tmpPos = src.find(pattern.substr(*posIter+2, *nxtIter - patternPos), sourcePos);
result.push_back(src.substr(sourcePos, tmpPos - sourcePos));
sourcePos = tmpPos;
}else{
result.push_back(src.substr(sourcePos));
sourcePos = std::string::npos;
}
posIter++;
}
return result.size() == positions.size();
}
}

6
lib/util.h Normal file
View file

@ -0,0 +1,6 @@
#include <string>
#include <deque>
namespace Util {
bool stringScan(const std::string & src, const std::string & pattern, std::deque<std::string> & result);
}