Skip to content

Commit

Permalink
Created a Smoother framework for configurable congestion control. Mov…
Browse files Browse the repository at this point in the history
…ed all CC-related parts of SRT to LiveSmoother. Restored abandoned UDT parts to be usable with FileSmoother.
  • Loading branch information
Mikołaj Małecki committed Sep 14, 2017
1 parent a398b53 commit 4cb5242
Show file tree
Hide file tree
Showing 21 changed files with 2,369 additions and 650 deletions.
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,11 @@ if ( ENABLE_CXX11 )
${SOURCES_transmit}
)

add_executable(sf
${CMAKE_SOURCE_DIR}/apps/sf.cpp
${SOURCES_transmit}
)

# Test programs
add_executable(utility-test ${CMAKE_SOURCE_DIR}/apps/utility-test.cpp)

Expand All @@ -462,6 +467,10 @@ if ( ENABLE_CXX11 )
target_link_libraries(siplex ${TARGET_srt} ${TARGET_haicrypt})
install(TARGETS siplex RUNTIME DESTINATION bin)

set_target_properties(sf PROPERTIES COMPILE_FLAGS "${CFLAGS_CXX_STANDARD} ${EXTRA_stransmit}")
target_link_libraries(sf ${TARGET_srt} ${TARGET_haicrypt})
install(TARGETS sf RUNTIME DESTINATION bin)

install(PROGRAMS scripts/sfplay DESTINATION bin)

target_link_libraries(utility-test ${TARGET_srt})
Expand Down
351 changes: 351 additions & 0 deletions apps/sf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@

#include <iostream>
#include <iterator>
#include <vector>
#include <map>
#include <stdexcept>
#include <string>
#include <thread>
#include <chrono>
#include <sys/stat.h>
#include <srt.h>
#include <udt.h>

#include "appcommon.hpp"
#include "uriparser.hpp"
#include "logsupport.hpp"
#include "socketoptions.hpp"
#include "transmitbase.hpp"
#include "transmitmedia.hpp"


bool Upload(UriParser& srt, UriParser& file);
bool Download(UriParser& srt, UriParser& file);

const logging::LogFA SRT_LOGFA_APP = 10;

size_t g_buffer_size = 1456;

int main( int argc, char** argv )
{
vector<OptionScheme> optargs = {
{ {"ll", "loglevel"}, OptionScheme::ARG_ONE },
{ {"b", "buffer"}, OptionScheme::ARG_ONE }
};
options_t params = ProcessOptions(argv, argc, optargs);

/*
cerr << "OPTIONS (DEBUG)\n";
for (auto o: params)
{
cerr << "[" << o.first << "] ";
copy(o.second.begin(), o.second.end(), ostream_iterator<string>(cerr, " "));
cerr << endl;
}
*/

vector<string> args = params[""];
if ( args.size() < 2 )
{
cerr << "Usage: " << argv[0] << " <source> <target>\n";
return 1;
}

string loglevel = Option<OutString>(params, "error", "ll", "loglevel");
logging::LogLevel::type lev = SrtParseLogLevel(loglevel);
UDT::setloglevel(lev);
UDT::addlogfa(SRT_LOGFA_APP);

string verbo = Option<OutString>(params, "no", "v", "verbose");
if ( verbo == "" || !false_names.count(verbo) )
::transmit_verbose = true;

string bs = Option<OutString>(params, "", "b", "buffer");
if ( bs != "" )
{
::g_buffer_size = stoi(bs);
}

string source = args[0];
string target = args[1];

UriParser us(source), ut(target);

Verb() << "SOURCE type=" << us.scheme() << ", TARGET type=" << ut.scheme();

try
{
if (us.scheme() == "srt")
{
if (ut.scheme() != "file")
{
cerr << "SRT to FILE should be specified\n";
return 1;
}
Download(us, ut);
}
else if (ut.scheme() == "srt")
{
if (us.scheme() != "file")
{
cerr << "FILE to SRT should be specified\n";
return 1;
}
Upload(ut, us);
}
else
{
cerr << "SRT URI must be one of given media.\n";
return 1;
}
}
catch (std::exception& x)
{
cerr << "ERROR: " << x.what() << endl;
return 1;
}


return 0;
}

void ExtractPath(string path, ref_t<string> dir, ref_t<string> fname)
{
//string& dir = r_dir;
//string& fname = r_fname;

string directory = path;
string filename = "";

struct stat state;
stat(path.c_str(), &state);
if (!S_ISDIR(state.st_mode))
{
// Extract directory as a butlast part of path
size_t pos = path.find_last_of("/");
if ( pos == string::npos )
{
filename = path;
directory = ".";
}
else
{
directory = path.substr(0, pos);
filename = path.substr(pos+1);
}
}

if (directory[0] != '/')
{
// Glue in the absolute prefix of the current directory
// to make it absolute. This is needed to properly interpret
// the fixed uri.
static const size_t MAX_PATH = 4096; // don't care how proper this is
char tmppath[MAX_PATH];
char* gwd = getcwd(tmppath, MAX_PATH);
if ( !gwd )
{
// Don't bother with that now. We need something better for that anyway.
throw std::invalid_argument("Path too long");
}
string wd = gwd;

directory = wd + "/" + directory;
}

dir = directory;
fname = filename;
}

bool DoUpload(UriParser& ut, string path, string filename)
{
SrtModel m(ut.host(), ut.portno(), ut.parameters());

string id = filename;
Verb() << "Passing '" << id << "' as stream ID\n";

m.Establish(Ref(id));

// Check if the filename was changed
if (id != filename)
{
cerr << "SRT caller has changed the filename '" << filename << "' to '" << id << "' - rejecting\n";
return false;
}

Verb() << "USING ID: " << id;

// SrtTarget* tp = new SrtTarget;
// tp->StealFrom(m);
// unique_ptr<Target> target(tp);

//SRTSOCKET ss = tp->Socket();
SRTSOCKET ss = m.Socket();

// Use a manual loop for reading from SRT
char buf[::g_buffer_size];

ifstream ifile(path);
if ( !ifile )
{
cerr << "Error opening file: '" << path << "'";
return false;
}

for (;;)
{
size_t n = ifile.read(buf, ::g_buffer_size).gcount();
if (n > 0)
{
Verb() << "Upload: --> " << n;
int st = srt_send(ss, buf, n, 0);
if (st == SRT_ERROR)
{
cerr << "Upload: SRT error: " << srt_getlasterror_str() << endl;
return false;
}
}

if (ifile.eof())
break;

if ( !ifile.good() )
{
cerr << "ERROR while reading file\n";
return false;
}
}

// send-flush-loop
for (;;)
{
size_t bytes;
size_t blocks;
int st = srt_getsndbuffer(ss, &blocks, &bytes);
if (st == SRT_ERROR)
{
cerr << "Error in srt_getsndbuffer: " << srt_getlasterror_str() << endl;
return false;
}
if (bytes == 0)
{
Verb() << "Sending buffer DEPLETED - ok.";
break;
}
Verb() << "Sending buffer still: bytes=" << bytes << " blocks=" << blocks;
this_thread::sleep_for(chrono::milliseconds(250));
}

return true;
}

bool DoDownload(UriParser& us, string directory, string filename)
{
SrtModel m(us.host(), us.portno(), us.parameters());

string id = filename;
m.Establish(Ref(id));

// Disregard the filename, unless the destination file exists.

string path = directory + "/" + id;
struct stat state;
if ( stat(path.c_str(), &state) == -1 )
{
switch ( errno )
{
case ENOENT:
// This is expected, go on.
break;

default:
cerr << "Download: error '" << errno << "'when checking destination location: " << path << endl;
return false;
}
}
else
{
// Check if destination is a regular file, of so, allow to overwrite.
// Otherwise reject.
if (!S_ISREG(state.st_mode))
{
cerr << "Download: target location '" << path << "' does not designate a regular file.\n";
return false;
}
}

ofstream ofile(path, ios::out | ios::trunc);
if ( !ofile.good() )
{
cerr << "Download: can't create output file: " << path;
return false;
}
SRTSOCKET ss = m.Socket();

Verb() << "Downloading from '" << us.uri() << "' to '" << path;

vector<char> buf(::g_buffer_size);

for (;;)
{
int n = srt_recv(ss, buf.data(), ::g_buffer_size, 0);
if (n == SRT_ERROR)
{
cerr << "Download: SRT error: " << srt_getlasterror_str() << endl;
return false;
}

if (n == 0)
{
Verb() << "Download COMPLETE.";
break;
}

// Write to file any amount of data received

Verb() << "Download: --> " << n;
ofile.write(buf.data(), n);
}

return true;
}

bool Upload(UriParser& srt_target_uri, UriParser& fileuri)
{
if ( fileuri.scheme() != "file" )
{
cerr << "Upload: source accepted only as a file\n";
return false;
}
// fileuri is source-reading file
// srt_target_uri is SRT target

string path = fileuri.path();
string directory, filename;
ExtractPath(path, ref(directory), ref(filename));
Verb() << "Extract path '" << path << "': directory=" << directory << " filename=" << filename;
// Set ID to the filename.
// Directory will be preserved.

// Add some extra parameters.
srt_target_uri["transtype"] = "file";

return DoUpload(srt_target_uri, path, filename);
}

bool Download(UriParser& srt_source_uri, UriParser& fileuri)
{
if (fileuri.scheme() != "file" )
{
cerr << "Download: target accepted only as a file\n";
return false;
}

string path = fileuri.path(), directory, filename;
ExtractPath(path, Ref(directory), Ref(filename));

srt_source_uri["transtype"] = "file";

return DoDownload(srt_source_uri, directory, filename);
}

5 changes: 5 additions & 0 deletions common/socketoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ using namespace std;
set<string> true_names = { "1", "yes", "on", "true" };
set<string> false_names = { "0", "no", "off", "false" };

std::map<std::string, int> enummap_transtype = {
{ "live", SRTT_LIVE },
{ "vod", SRTT_VOD },
{ "file", SRTT_VOD }
};

SocketOption::Mode SrtConfigurePre(SRTSOCKET socket, string host, map<string, string> options, vector<string>* failures)
{
Expand Down
Loading

0 comments on commit 4cb5242

Please sign in to comment.