Fully implemented DTSC pull support
This commit is contained in:
parent
668560ff05
commit
dda0ea669c
27 changed files with 930 additions and 272 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
40
lib/util.cpp
Normal 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
6
lib/util.h
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue