/// Starts a loop, waiting for connections to send data to. int Start(int argc, char ** argv) { Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION); conf.addOption("stream_name", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Name of the stream this buffer will be providing.\"}")); conf.addOption("awaiting_ip", JSON::fromString("{\"arg_num\":2, \"arg\":\"string\", \"default\":\"\", \"help\":\"IP address to expect incoming data from. This will completely disable reading from standard input if used.\"}")); conf.addOption("reportstats", JSON::fromString("{\"default\":0, \"help\":\"Report stats to a controller process.\", \"short\":\"s\", \"long\":\"reportstats\"}")); conf.parseArgs(argc, argv); std::string name = conf.getString("stream_name"); SS = Util::Stream::makeLive(name); if (!SS.connected()) { perror("Could not create stream socket"); return 1; } conf.activate(); thisStream = Stream::get(); thisStream->setName(name); Socket::Connection incoming; Socket::Connection std_input(fileno(stdin)); tthread::thread * StatsThread = 0; if (conf.getBool("reportstats")){StatsThread = new tthread::thread(handleStats, 0);} tthread::thread * StdinThread = 0; std::string await_ip = conf.getString("awaiting_ip"); if (await_ip == ""){ StdinThread = new tthread::thread(handleStdin, 0); }else{ thisStream->setWaitingIP(await_ip); StdinThread = new tthread::thread(handlePushin, 0); } while (buffer_running && SS.connected() && conf.is_active){ //check for new connections, accept them if there are any //starts a thread for every accepted connection incoming = SS.accept(true); if (incoming.connected()){ user * usr_ptr = new user(incoming); thisStream->addUser(usr_ptr); usr_ptr->Thread = new tthread::thread(handleUser, (void *)usr_ptr); } }//main loop // disconnect listener buffer_running = false; std::cout << "End of input file - buffer shutting down" << std::endl; SS.close(); if (StatsThread){StatsThread->join();} StdinThread->join(); delete thisStream; return 0; }
/// Loop reading DTSC data from stdin and processing it at the correct speed. void handleStdin(void * empty){ if (empty != 0){return;} long long int timeDiff = 0;//difference between local time and stream time unsigned int lastPacket = 0;//last parsed packet timestamp std::string inBuffer; char charBuffer[1024*10]; unsigned int charCount; long long int now; while (std::cin.good() && buffer_running){ //slow down packet receiving to real-time now = getNowMS(); if ((now - timeDiff >= lastPacket) || (lastPacket - (now - timeDiff) > 15000)){ thisStream->getWriteLock(); if (thisStream->getStream()->parsePacket(inBuffer)){ thisStream->getStream()->outPacket(0); lastPacket = thisStream->getStream()->getTime(); if ((now - timeDiff - lastPacket) > 15000 || (now - timeDiff - lastPacket < -15000)){ timeDiff = now - lastPacket; } thisStream->dropWriteLock(true); }else{ thisStream->dropWriteLock(false); std::cin.read(charBuffer, 1024*10); charCount = std::cin.gcount(); inBuffer.append(charBuffer, charCount); } }else{ usleep(std::min(14999LL, lastPacket - (now - timeDiff)) * 1000); } } buffer_running = false; SS.close(); }
/// Loop reading DTSC data from an IP push address. /// No changes to the speed are made. void handlePushin(void * empty){ if (empty != 0){return;} while (buffer_running){ if (thisStream->getIPInput().connected()){ if (thisStream->getIPInput().spool()){ thisStream->getWriteLock(); if (thisStream->getStream()->parsePacket(thisStream->getIPInput().Received().get())){ thisStream->getStream()->outPacket(0); thisStream->dropWriteLock(true); }else{ thisStream->dropWriteLock(false); usleep(1000);//1ms wait } }else{ usleep(1000);//1ms wait } }else{ usleep(1000000);//1s wait } } SS.close(); }
namespace Buffer{ volatile bool buffer_running = true; ///< Set to false when shutting down. Stream * thisStream = 0; Socket::Server SS; ///< The server socket. /// Gets the current system time in milliseconds. long long int getNowMS(){ timeval t; gettimeofday(&t, 0); return t.tv_sec * 1000 + t.tv_usec/1000; }//getNowMS void handleStats(void * empty){ if (empty != 0){return;} std::string double_newline = "\n\n"; Socket::Connection StatsSocket = Socket::Connection("/tmp/mist/statistics", true); while (buffer_running){ usleep(1000000); //sleep one second if (!StatsSocket.connected()){ StatsSocket = Socket::Connection("/tmp/mist/statistics", true); } if (StatsSocket.connected()){ StatsSocket.Send(Stream::get()->getStats()); StatsSocket.Send(double_newline); StatsSocket.flush(); } } StatsSocket.close(); } void handleUser(void * v_usr){ user * usr = (user*)v_usr; #if DEBUG >= 4 std::cerr << "Thread launched for user " << usr->MyStr << ", socket number " << usr->S.getSocket() << std::endl; #endif usr->myRing = thisStream->getRing(); usr->S.Send(thisStream->getHeader()); usr->S.flush(); while (usr->S.connected()){ usleep(5000); //sleep 5ms usr->Send(); if (usr->S.spool() && usr->S.Received().size()){ //delete anything that doesn't end with a newline if (!usr->S.Received().get().empty() && *(usr->S.Received().get().rbegin()) != '\n'){ usr->S.Received().get().clear(); continue; } usr->S.Received().get().resize(usr->S.Received().get().size() - 1); if (!usr->S.Received().get().empty()){ switch (usr->S.Received().get()[0]){ case 'P':{ //Push std::cout << "Push attempt from IP " << usr->S.Received().get().substr(2) << std::endl; if (thisStream->checkWaitingIP(usr->S.Received().get().substr(2))){ if (thisStream->setInput(usr->S)){ std::cout << "Push accepted!" << std::endl; usr->S = Socket::Connection(-1); return; }else{ usr->Disconnect("Push denied - push already in progress!"); } }else{ usr->Disconnect("Push denied - invalid IP address!"); } } break; case 'S':{ //Stats usr->tmpStats = Stats(usr->S.Received().get().substr(2)); unsigned int secs = usr->tmpStats.conntime - usr->lastStats.conntime; if (secs < 1){secs = 1;} usr->curr_up = (usr->tmpStats.up - usr->lastStats.up) / secs; usr->curr_down = (usr->tmpStats.down - usr->lastStats.down) / secs; usr->lastStats = usr->tmpStats; thisStream->saveStats(usr->MyStr, usr->tmpStats); } break; case 's':{ //second-seek //ignored for now } break; case 'f':{ //frame-seek //ignored for now } break; case 'p':{ //play //ignored for now } break; case 'o':{ //once-play //ignored for now } break; case 'q':{ //quit-playing //ignored for now } break; } } } } usr->Disconnect("Socket closed."); thisStream->cleanUsers(); } /// Loop reading DTSC data from stdin and processing it at the correct speed. void handleStdin(void * empty){ if (empty != 0){return;} long long int timeDiff = 0;//difference between local time and stream time unsigned int lastPacket = 0;//last parsed packet timestamp std::string inBuffer; char charBuffer[1024*10]; unsigned int charCount; long long int now; while (std::cin.good() && buffer_running){ //slow down packet receiving to real-time now = getNowMS(); if ((now - timeDiff >= lastPacket) || (lastPacket - (now - timeDiff) > 15000)){ thisStream->getWriteLock(); if (thisStream->getStream()->parsePacket(inBuffer)){ thisStream->getStream()->outPacket(0); lastPacket = thisStream->getStream()->getTime(); if ((now - timeDiff - lastPacket) > 15000 || (now - timeDiff - lastPacket < -15000)){ timeDiff = now - lastPacket; } thisStream->dropWriteLock(true); }else{ thisStream->dropWriteLock(false); std::cin.read(charBuffer, 1024*10); charCount = std::cin.gcount(); inBuffer.append(charBuffer, charCount); } }else{ usleep(std::min(14999LL, lastPacket - (now - timeDiff)) * 1000); } } buffer_running = false; SS.close(); } /// Loop reading DTSC data from an IP push address. /// No changes to the speed are made. void handlePushin(void * empty){ if (empty != 0){return;} while (buffer_running){ if (thisStream->getIPInput().connected()){ if (thisStream->getIPInput().spool()){ thisStream->getWriteLock(); if (thisStream->getStream()->parsePacket(thisStream->getIPInput().Received().get())){ thisStream->getStream()->outPacket(0); thisStream->dropWriteLock(true); }else{ thisStream->dropWriteLock(false); usleep(1000);//1ms wait } }else{ usleep(1000);//1ms wait } }else{ usleep(1000000);//1s wait } } SS.close(); } /// Starts a loop, waiting for connections to send data to. int Start(int argc, char ** argv) { Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION); conf.addOption("stream_name", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Name of the stream this buffer will be providing.\"}")); conf.addOption("awaiting_ip", JSON::fromString("{\"arg_num\":2, \"arg\":\"string\", \"default\":\"\", \"help\":\"IP address to expect incoming data from. This will completely disable reading from standard input if used.\"}")); conf.addOption("reportstats", JSON::fromString("{\"default\":0, \"help\":\"Report stats to a controller process.\", \"short\":\"s\", \"long\":\"reportstats\"}")); conf.parseArgs(argc, argv); std::string name = conf.getString("stream_name"); SS = Util::Stream::makeLive(name); if (!SS.connected()) { perror("Could not create stream socket"); return 1; } conf.activate(); thisStream = Stream::get(); thisStream->setName(name); Socket::Connection incoming; Socket::Connection std_input(fileno(stdin)); tthread::thread * StatsThread = 0; if (conf.getBool("reportstats")){StatsThread = new tthread::thread(handleStats, 0);} tthread::thread * StdinThread = 0; std::string await_ip = conf.getString("awaiting_ip"); if (await_ip == ""){ StdinThread = new tthread::thread(handleStdin, 0); }else{ thisStream->setWaitingIP(await_ip); StdinThread = new tthread::thread(handlePushin, 0); } while (buffer_running && SS.connected() && conf.is_active){ //check for new connections, accept them if there are any //starts a thread for every accepted connection incoming = SS.accept(true); if (incoming.connected()){ user * usr_ptr = new user(incoming); thisStream->addUser(usr_ptr); usr_ptr->Thread = new tthread::thread(handleUser, (void *)usr_ptr); } }//main loop // disconnect listener buffer_running = false; std::cout << "End of input file - buffer shutting down" << std::endl; SS.close(); if (StatsThread){StatsThread->join();} StdinThread->join(); delete thisStream; return 0; } };//Buffer namespace
namespace Buffer { volatile bool buffer_running = true; ///< Set to false when shutting down. Stream * thisStream = 0; Socket::Server SS; ///< The server socket. ///\brief A function running in a thread to send all statistics. ///\param empty A null pointer. void handleStats(void * empty){ if (empty != 0){ return; } std::string double_newline = "\n\n"; Socket::Connection StatsSocket = Socket::Connection("/tmp/mist/statistics", true); while (buffer_running){ Util::sleep(1000); //sleep one second if ( !StatsSocket.connected()){ StatsSocket = Socket::Connection("/tmp/mist/statistics", true); } if (StatsSocket.connected()){ Stream::get()->getReadLock(); StatsSocket.Send(Stream::get()->getStats()); Stream::get()->dropReadLock(); StatsSocket.SendNow(double_newline); } } StatsSocket.close(); } ///\brief A function running in a thread to handle a new user connection. ///\param v_usr The user that is connected. void handleUser(void * v_usr){ user * usr = (user*)v_usr; thisStream->addUser(usr); #if DEBUG >= 5 std::cerr << "Thread launched for user " << usr->MyStr << ", socket number " << usr->S.getSocket() << std::endl; #endif Stream::get()->getReadLock(); usr->myRing = thisStream->getRing(); if (thisStream->getStream()->metadata && thisStream->getHeader().size() > 0){ usr->S.SendNow(thisStream->getHeader()); } Stream::get()->dropReadLock(); while (usr->S.connected()){ Util::sleep(5); //sleep 5ms if ( !usr->myRing->playCount || !usr->Send()){ if (usr->myRing->updated){ Stream::get()->getReadLock(); usr->S.SendNow(Stream::get()->getStream()->metadata.toNetPacked()); Stream::get()->dropReadLock(); usr->myRing->updated = false; } if (usr->S.spool()){ while (usr->S.Received().size()){ //delete anything that doesn't end with a newline if ( !usr->S.Received().get().empty() && *(usr->S.Received().get().rbegin()) != '\n'){ usr->S.Received().get().clear(); continue; } usr->S.Received().get().resize(usr->S.Received().get().size() - 1); if ( !usr->S.Received().get().empty()){ switch (usr->S.Received().get()[0]){ case 'P': { //Push std::cout << "Push attempt from IP " << usr->S.Received().get().substr(2) << std::endl; if (thisStream->checkWaitingIP(usr->S.Received().get().substr(2))){ usr->S.Received().get().clear(); if (thisStream->setInput(usr->S)){ std::cout << "Push accepted!" << std::endl; usr->S = Socket::Connection( -1); return; }else{ usr->Disconnect("Push denied - push already in progress!"); } }else{ usr->Disconnect("Push denied - invalid IP address!"); } break; } case 'S': { //Stats usr->tmpStats = Stats(usr->S.Received().get().substr(2)); unsigned int secs = usr->tmpStats.conntime - usr->lastStats.conntime; if (secs < 1){ secs = 1; } usr->curr_up = (usr->tmpStats.up - usr->lastStats.up) / secs; usr->curr_down = (usr->tmpStats.down - usr->lastStats.down) / secs; usr->lastStats = usr->tmpStats; thisStream->saveStats(usr->MyStr, usr->tmpStats); break; } case 's': { //second-seek unsigned int ms = JSON::Value(usr->S.Received().get().substr(2)).asInt(); usr->myRing->waiting = false; usr->myRing->starved = false; usr->myRing->b = thisStream->getStream()->msSeek(ms); if (usr->myRing->playCount > 0){ usr->myRing->playCount = 0; } break; } case 'f': { //frame-seek unsigned int frameno = JSON::Value(usr->S.Received().get().substr(2)).asInt(); usr->myRing->waiting = false; usr->myRing->starved = false; usr->myRing->b = thisStream->getStream()->frameSeek(frameno); if (usr->myRing->playCount > 0){ usr->myRing->playCount = 0; } break; } case 'p': { //play usr->myRing->playCount = -1; break; } case 'o': { //once-play if (usr->myRing->playCount >= 0){ usr->myRing->playCount++; } break; } case 'q': { //quit-playing usr->myRing->playCount = 0; break; } } usr->S.Received().get().clear(); } } } } } usr->Disconnect("Socket closed."); thisStream->removeUser(usr); } ///\brief A function running a thread to handle input data through stdin. /// ///Automatically slows down to realtime playback. ///\param empty A null pointer. void handleStdin(void * empty){ if (empty != 0){ return; } long long int timeDiff = 0; //difference between local time and stream time unsigned int lastPacket = 0; //last parsed packet timestamp std::string inBuffer; char charBuffer[1024 * 10]; unsigned int charCount; long long int now; while (std::cin.good() && buffer_running){ //slow down packet receiving to real-time now = Util::getMS(); if (((now - timeDiff) >= lastPacket) || (lastPacket - (now - timeDiff) > 15000)){ thisStream->getWriteLock(); if (thisStream->getStream()->parsePacket(inBuffer)){ thisStream->getStream()->outPacket(0); lastPacket = thisStream->getStream()->getTime(); if ((now - timeDiff - lastPacket) > 15000 || (now - timeDiff - lastPacket < -15000)){ timeDiff = now - lastPacket; } thisStream->dropWriteLock(true); }else{ thisStream->dropWriteLock(false); std::cin.read(charBuffer, 1024 * 10); charCount = std::cin.gcount(); inBuffer.append(charBuffer, charCount); } }else{ Util::sleep(std::min(15LL, lastPacket - (now - timeDiff))); } } buffer_running = false; } ///\brief A function running a thread to handle input data through rtmp push. ///\param empty A null pointer. void handlePushin(void * empty){ if (empty != 0){ return; } while (buffer_running){ if (thisStream->getIPInput().connected()){ if (thisStream->getIPInput().spool()){ bool packed_parsed = false; do{ thisStream->getWriteLock(); if (thisStream->getStream()->parsePacket(thisStream->getIPInput().Received())){ thisStream->getStream()->outPacket(0); thisStream->dropWriteLock(true); packed_parsed = true; }else{ thisStream->dropWriteLock(false); packed_parsed = false; Util::sleep(1); //1ms wait } }while (packed_parsed); }else{ Util::sleep(1); //1ms wait } }else{ Util::sleep(1000); //1s wait } } } ///\brief Starts a loop, waiting for connections to send data to. ///\param argc The number of arguments to the program. ///\param argv The arguments to the program. ///\return The return code of the buffer. int Start(int argc, char ** argv){ /*std::ofstream myfile ("/home/sharvanath/mistserver/test.txt",std::ios::app); //struct sockaddr add; //socklen_t add_length=sizeof(struct sockaddr); //getsockname(incoming.sock, &add,&add_length); myfile<<"hello1\n"; //myfile << "the family here is : "<<add.sa_family<<"\n"; myfile.close(); */ Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION); conf.addOption("stream_name", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Name of the stream this buffer will be providing.\"}")); conf.addOption("awaiting_ip", JSON::fromString( "{\"arg_num\":2, \"arg\":\"string\", \"default\":\"\", \"help\":\"IP address to expect incoming data from. This will completely disable reading from standard input if used.\"}")); conf.addOption("reportstats", JSON::fromString("{\"default\":0, \"help\":\"Report stats to a controller process.\", \"short\":\"s\", \"long\":\"reportstats\"}")); conf.addOption("time", JSON::fromString( "{\"default\":0, \"arg\": \"integer\", \"help\":\"Buffer a specied amount of time in ms.\", \"short\":\"t\", \"long\":\"time\"}")); conf.parseArgs(argc, argv); std::string name = conf.getString("stream_name"); SS = Util::Stream::makeLive(name); if ( !SS.connected()){ perror("Could not create stream socket"); return 1; } SS.setBlocking(false); conf.activate(); thisStream = Stream::get(); thisStream->setName(name); thisStream->getStream()->setBufferTime(conf.getInteger("time")); Socket::Connection incoming; Socket::Connection std_input(fileno(stdin)); if (conf.getBool("reportstats")){ tthread::thread StatsThread(handleStats, 0); StatsThread.detach(); } std::string await_ip = conf.getString("awaiting_ip"); if (await_ip == ""){ tthread::thread StdinThread(handleStdin, 0); StdinThread.detach(); }else{ thisStream->setWaitingIP(await_ip); tthread::thread StdinThread(handlePushin, 0); StdinThread.detach(); } while (buffer_running && SS.connected() && conf.is_active){ //check for new connections, accept them if there are any //starts a thread for every accepted connection //sharva_mod incoming = SS.accept(true); if (incoming.connected()){ tthread::thread thisUser(handleUser, (void *)new user(incoming)); thisUser.detach(); }else{ Util::sleep(50);//sleep 50ms } } //main loop // disconnect listener buffer_running = false; std::cout << "Buffer shutting down" << std::endl; SS.close(); if (thisStream->getIPInput().connected()){ thisStream->getIPInput().close(); } delete thisStream; return 0; } } //Buffer namespace
///\brief Starts a loop, waiting for connections to send data to. ///\param argc The number of arguments to the program. ///\param argv The arguments to the program. ///\return The return code of the buffer. int Start(int argc, char ** argv){ /*std::ofstream myfile ("/home/sharvanath/mistserver/test.txt",std::ios::app); //struct sockaddr add; //socklen_t add_length=sizeof(struct sockaddr); //getsockname(incoming.sock, &add,&add_length); myfile<<"hello1\n"; //myfile << "the family here is : "<<add.sa_family<<"\n"; myfile.close(); */ Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION); conf.addOption("stream_name", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Name of the stream this buffer will be providing.\"}")); conf.addOption("awaiting_ip", JSON::fromString( "{\"arg_num\":2, \"arg\":\"string\", \"default\":\"\", \"help\":\"IP address to expect incoming data from. This will completely disable reading from standard input if used.\"}")); conf.addOption("reportstats", JSON::fromString("{\"default\":0, \"help\":\"Report stats to a controller process.\", \"short\":\"s\", \"long\":\"reportstats\"}")); conf.addOption("time", JSON::fromString( "{\"default\":0, \"arg\": \"integer\", \"help\":\"Buffer a specied amount of time in ms.\", \"short\":\"t\", \"long\":\"time\"}")); conf.parseArgs(argc, argv); std::string name = conf.getString("stream_name"); SS = Util::Stream::makeLive(name); if ( !SS.connected()){ perror("Could not create stream socket"); return 1; } SS.setBlocking(false); conf.activate(); thisStream = Stream::get(); thisStream->setName(name); thisStream->getStream()->setBufferTime(conf.getInteger("time")); Socket::Connection incoming; Socket::Connection std_input(fileno(stdin)); if (conf.getBool("reportstats")){ tthread::thread StatsThread(handleStats, 0); StatsThread.detach(); } std::string await_ip = conf.getString("awaiting_ip"); if (await_ip == ""){ tthread::thread StdinThread(handleStdin, 0); StdinThread.detach(); }else{ thisStream->setWaitingIP(await_ip); tthread::thread StdinThread(handlePushin, 0); StdinThread.detach(); } while (buffer_running && SS.connected() && conf.is_active){ //check for new connections, accept them if there are any //starts a thread for every accepted connection //sharva_mod incoming = SS.accept(true); if (incoming.connected()){ tthread::thread thisUser(handleUser, (void *)new user(incoming)); thisUser.detach(); }else{ Util::sleep(50);//sleep 50ms } } //main loop // disconnect listener buffer_running = false; std::cout << "Buffer shutting down" << std::endl; SS.close(); if (thisStream->getIPInput().connected()){ thisStream->getIPInput().close(); } delete thisStream; return 0; }