DTSC push output support, fixes for DTSC push input and DTSC pull output
This commit is contained in:
parent
77aa90d48c
commit
ea49344628
4 changed files with 195 additions and 104 deletions
|
@ -6,12 +6,49 @@
|
|||
#include <mist/defines.h>
|
||||
#include <mist/stream.h>
|
||||
#include <mist/triggers.h>
|
||||
#include <mist/http_parser.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace Mist{
|
||||
OutDTSC::OutDTSC(Socket::Connection &conn) : Output(conn){
|
||||
setBlocking(true);
|
||||
JSON::Value prep;
|
||||
if (config->getString("target").size()){
|
||||
streamName = config->getString("streamname");
|
||||
pushUrl = HTTP::URL(config->getString("target"));
|
||||
if (pushUrl.protocol != "dtsc"){
|
||||
onFail("Target must start with dtsc://", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pushUrl.path.size()){pushUrl.path = streamName;}
|
||||
INFO_MSG("About to push stream %s out. Host: %s, port: %d, target stream: %s", streamName.c_str(),
|
||||
pushUrl.host.c_str(), pushUrl.getPort(), pushUrl.path.c_str());
|
||||
myConn.close();
|
||||
myConn.Received().clear();
|
||||
myConn.open(pushUrl.host, pushUrl.getPort(), true);
|
||||
initialize();
|
||||
initialSeek();
|
||||
if (!myConn){
|
||||
onFail("Could not start push, aborting", true);
|
||||
return;
|
||||
}
|
||||
prep["cmd"] = "push";
|
||||
prep["version"] = APPIDENT;
|
||||
prep["stream"] = pushUrl.path;
|
||||
std::map<std::string, std::string> args;
|
||||
HTTP::parseVars(pushUrl.args, args);
|
||||
if (args.count("pass")){prep["password"] = args["pass"];}
|
||||
if (args.count("pw")){prep["password"] = args["pw"];}
|
||||
if (args.count("password")){prep["password"] = args["password"];}
|
||||
if (pushUrl.pass.size()){prep["password"] = pushUrl.pass;}
|
||||
sendCmd(prep);
|
||||
wantRequest = true;
|
||||
parseData = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
setBlocking(true);
|
||||
prep["cmd"] = "hi";
|
||||
prep["version"] = APPIDENT;
|
||||
prep["pack_method"] = 2;
|
||||
|
@ -58,6 +95,19 @@ namespace Mist{
|
|||
capa["desc"] = "Real time streaming over DTSC (proprietary protocol for efficient inter-server streaming)";
|
||||
capa["deps"] = "";
|
||||
capa["codecs"][0u][0u].append("+*");
|
||||
capa["push_urls"].append("dtsc://*");
|
||||
capa["incoming_push_url"] = "dtsc://$host:$port/$stream?pass=$password";
|
||||
|
||||
JSON::Value opt;
|
||||
opt["arg"] = "string";
|
||||
opt["default"] = "";
|
||||
opt["arg_num"] = 1;
|
||||
opt["help"] = "Target DTSC URL to push out towards.";
|
||||
cfg->addOption("target", opt);
|
||||
cfg->addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":"
|
||||
"\"stream\",\"help\":\"The name of the stream to "
|
||||
"push out, when pushing out.\"}"));
|
||||
|
||||
cfg->addConnectorOptions(4200, capa);
|
||||
config = cfg;
|
||||
}
|
||||
|
@ -123,14 +173,9 @@ namespace Mist{
|
|||
|
||||
void OutDTSC::sendHeader(){
|
||||
sentHeader = true;
|
||||
userSelect.clear();
|
||||
std::set<size_t> validTracks = M.getValidTracks();
|
||||
std::set<size_t> selectedTracks;
|
||||
for (std::set<size_t>::iterator it = validTracks.begin(); it != validTracks.end(); it++){
|
||||
if (M.getType(*it) == "video" || M.getType(*it) == "audio"){
|
||||
userSelect[*it].reload(streamName, *it);
|
||||
selectedTracks.insert(*it);
|
||||
}
|
||||
for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
|
||||
selectedTracks.insert(it->first);
|
||||
}
|
||||
M.send(myConn, true, selectedTracks, true);
|
||||
if (M.getLive()){realTime = 0;}
|
||||
|
@ -154,7 +199,7 @@ namespace Mist{
|
|||
myConn.Received().remove(8);
|
||||
std::string dataPacket = myConn.Received().remove(rSize);
|
||||
DTSC::Scan dScan((char *)dataPacket.data(), rSize);
|
||||
INFO_MSG("Received DTCM: %s", dScan.asJSON().toString().c_str());
|
||||
HIGH_MSG("Received DTCM: %s", dScan.asJSON().toString().c_str());
|
||||
if (dScan.getMember("cmd").asString() == "push"){
|
||||
handlePush(dScan);
|
||||
continue;
|
||||
|
@ -171,12 +216,16 @@ namespace Mist{
|
|||
INFO_MSG("Ok: %s", dScan.getMember("msg").asString().c_str());
|
||||
continue;
|
||||
}
|
||||
if (dScan.getMember("cmd").asString() == "hi"){
|
||||
INFO_MSG("Connected to server running version %s", dScan.getMember("version").asString().c_str());
|
||||
continue;
|
||||
}
|
||||
if (dScan.getMember("cmd").asString() == "error"){
|
||||
ERROR_MSG("%s", dScan.getMember("msg").asString().c_str());
|
||||
continue;
|
||||
}
|
||||
if (dScan.getMember("cmd").asString() == "reset"){
|
||||
meta.reInit(streamName);
|
||||
userSelect.clear();
|
||||
sendOk("Internal state reset");
|
||||
continue;
|
||||
}
|
||||
|
@ -192,9 +241,24 @@ namespace Mist{
|
|||
if (!myConn.Received().available(8 + rSize)){return;}// abort - not enough data yet
|
||||
std::string dataPacket = myConn.Received().remove(8 + rSize);
|
||||
DTSC::Packet metaPack(dataPacket.data(), dataPacket.size());
|
||||
meta.reInit(streamName, metaPack.getScan());
|
||||
DTSC::Scan metaScan = metaPack.getScan();
|
||||
meta.refresh();
|
||||
size_t prevTracks = meta.getValidTracks().size();
|
||||
|
||||
size_t tNum = metaScan.getMember("tracks").getSize();
|
||||
for (int i = 0; i < tNum; i++){
|
||||
DTSC::Scan trk = metaScan.getMember("tracks").getIndice(i);
|
||||
size_t trackID = trk.getMember("trackid").asInt();
|
||||
if (meta.trackIDToIndex(trackID, getpid()) == INVALID_TRACK_ID){
|
||||
MEDIUM_MSG("Adding track: %s", trk.asJSON().toString().c_str());
|
||||
meta.addTrackFrom(trk);
|
||||
}else{
|
||||
HIGH_MSG("Already had track: %s", trk.asJSON().toString().c_str());
|
||||
}
|
||||
}
|
||||
meta.refresh();
|
||||
std::stringstream rep;
|
||||
rep << "DTSC_HEAD received with " << M.getValidTracks().size() << " tracks. Bring on those data packets!";
|
||||
rep << "DTSC_HEAD parsed, we went from " << prevTracks << " to " << meta.getValidTracks().size() << " tracks. Bring on those data packets!";
|
||||
sendOk(rep.str());
|
||||
}else if (myConn.Received().copy(4) == "DTP2"){
|
||||
if (!isPushing()){
|
||||
|
@ -207,11 +271,19 @@ namespace Mist{
|
|||
if (!myConn.Received().available(8 + rSize)){return;}// abort - not enough data yet
|
||||
std::string dataPacket = myConn.Received().remove(8 + rSize);
|
||||
DTSC::Packet inPack(dataPacket.data(), dataPacket.size(), true);
|
||||
if (M.trackIDToIndex(inPack.getTrackId(), getpid()) == INVALID_TRACK_ID){
|
||||
onFail("DTSC_V2 received for a track that was not announced in the DTSC_HEAD!", true);
|
||||
size_t tid = M.trackIDToIndex(inPack.getTrackId(), getpid());
|
||||
if (tid == INVALID_TRACK_ID){
|
||||
//WARN_MSG("Received data for unknown track: %zu", inPack.getTrackId());
|
||||
onFail("DTSC_V2 received for a track that was not announced in a header!", true);
|
||||
return;
|
||||
}
|
||||
bufferLivePacket(inPack);
|
||||
if (!userSelect.count(tid)){
|
||||
userSelect[tid].reload(streamName, tid, COMM_STATUS_SOURCE);
|
||||
}
|
||||
char *data;
|
||||
size_t dataLen;
|
||||
inPack.getString("data", data, dataLen);
|
||||
bufferLivePacket(inPack.getTime(), inPack.getInt("offset"), tid, data, dataLen, inPack.getInt("bpos"), inPack.getFlag("keyframe"));
|
||||
}else{
|
||||
// Invalid
|
||||
onFail("Invalid packet header received. Aborting.", true);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "output.h"
|
||||
#include <mist/url.h>
|
||||
|
||||
namespace Mist{
|
||||
|
||||
|
@ -11,6 +12,7 @@ namespace Mist{
|
|||
void sendNext();
|
||||
void sendHeader();
|
||||
void initialSeek();
|
||||
static bool listenMode(){return !(config->getString("target").size());}
|
||||
void onFail(const std::string &msg, bool critical = false);
|
||||
void stats(bool force = false);
|
||||
void sendCmd(const JSON::Value &data);
|
||||
|
@ -20,6 +22,7 @@ namespace Mist{
|
|||
unsigned int lastActive; ///< Time of last sending of data.
|
||||
std::string getStatsName();
|
||||
std::string salt;
|
||||
HTTP::URL pushUrl;
|
||||
void handlePush(DTSC::Scan &dScan);
|
||||
void handlePlay(DTSC::Scan &dScan);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue