int main(int argc, char ** argv){ Util::Config conf(argv[0], PACKAGE_VERSION); conf.addConnectorOptions(1935); conf.parseArgs(argc, argv); Socket::Server server_socket = Socket::Server("/tmp/mist/http_smooth"); if ( !server_socket.connected()){ return 1; } conf.activate(); while (server_socket.connected() && conf.is_active){ Socket::Connection S = server_socket.accept(); if (S.connected()){ //check if the new connection is valid pid_t myid = fork(); if (myid == 0){ //if new child, start MAINHANDLER return Connector_HTTP::Connector_HTTP_Dynamic(S); }else{ //otherwise, do nothing or output debugging text #if DEBUG >= 3 fprintf(stderr, "Spawned new process %i for socket %i\n", (int)myid, S.getSocket()); #endif } } } //while connected server_socket.close(); return 0; } //main
int main(int argc, char ** argv){ Util::Config conf(argv[0], PACKAGE_VERSION); conf.addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"arg_num\":1,\"help\":\"The name of the stream that this connector will transmit.\"}")); conf.addConnectorOptions(8888); conf.parseArgs(argc, argv); Socket::Server server_socket = Socket::Server(conf.getInteger("listen_port"), conf.getString("listen_interface")); if ( !server_socket.connected()){ return 1; } conf.activate(); while (server_socket.connected() && conf.is_active){ Socket::Connection S = server_socket.accept(); if (S.connected()){ //check if the new connection is valid pid_t myid = fork(); if (myid == 0){ //if new child, start MAINHANDLER return Connector_TS::tsConnector(S, conf.getString("streamname")); }else{ //otherwise, do nothing or output debugging text #if DEBUG >= 5 fprintf(stderr, "Spawned new process %i for socket %i\n", (int)myid, S.getSocket()); #endif } } } //while connected server_socket.close(); return 0; } //main
int main(int argc, char ** argv){ Util::Config conf(argv[0], PACKAGE_VERSION); JSON::Value capa; capa["desc"] = "Enables the raw MPEG Transport Stream protocol over TCP."; capa["deps"] = ""; capa["required"]["streamname"]["name"] = "Stream"; capa["required"]["streamname"]["help"] = "What streamname to serve. For multiple streams, add this protocol multiple times using different ports."; capa["required"]["streamname"]["type"] = "str"; capa["required"]["streamname"]["option"] = "--stream"; capa["optional"]["tracks"]["name"] = "Tracks"; capa["optional"]["tracks"]["help"] = "The track IDs of the stream that this connector will transmit separated by spaces"; capa["optional"]["tracks"]["type"] = "str"; capa["optional"]["tracks"]["option"] = "--tracks"; conf.addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}")); conf.addOption("tracks", JSON::fromString("{\"arg\":\"string\",\"value\":[\"\"],\"short\": \"t\",\"long\":\"tracks\",\"help\":\"The track IDs of the stream that this connector will transmit separated by spaces.\"}")); conf.addConnectorOptions(8888, capa); bool ret = conf.parseArgs(argc, argv); if (conf.getBool("json")){ std::cout << capa.toString() << std::endl; return -1; } if (!ret){ std::cerr << "Usage error: missing argument(s)." << std::endl; conf.printHelp(std::cout); return 1; } Socket::Server server_socket = Socket::Server(conf.getInteger("listen_port"), conf.getString("listen_interface")); if ( !server_socket.connected()){ return 1; } conf.activate(); while (server_socket.connected() && conf.is_active){ Socket::Connection S = server_socket.accept(); if (S.connected()){ //check if the new connection is valid pid_t myid = fork(); if (myid == 0){ //if new child, start MAINHANDLER return Connector_TS::tsConnector(S, conf.getString("streamname"), conf.getString("tracks")); }else{ //otherwise, do nothing or output debugging text #if DEBUG >= 5 fprintf(stderr, "Spawned new process %i for socket %i\n", (int)myid, S.getSocket()); #endif } } } //while connected server_socket.close(); return 0; } //main
///\brief The standard process-spawning main function. int main(int argc, char ** argv){ Util::Config conf(argv[0], PACKAGE_VERSION); JSON::Value capa; capa["desc"] = "Enables the RTMP protocol which is used by Adobe Flash Player."; capa["deps"] = ""; capa["url_rel"] = "/play/$"; capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][0u].append("H263"); capa["codecs"][0u][0u].append("VP6"); capa["codecs"][0u][1u].append("AAC"); capa["codecs"][0u][1u].append("MP3"); capa["methods"][0u]["handler"] = "rtmp"; capa["methods"][0u]["type"] = "flash/10"; capa["methods"][0u]["priority"] = 6ll; conf.addConnectorOptions(1935, capa); conf.parseArgs(argc, argv); if (conf.getBool("json")){ std::cout << capa.toString() << std::endl; return -1; } Socket::Server server_socket = Socket::Server(conf.getInteger("listen_port"), conf.getString("listen_interface")); if ( !server_socket.connected()){ return 1; } conf.activate(); while (server_socket.connected() && conf.is_active){ Socket::Connection S = server_socket.accept(); if (S.connected()){ //check if the new connection is valid pid_t myid = fork(); if (myid == 0){ //if new child, start MAINHANDLER return Connector_RTMP::rtmpConnector(S); }else{ //otherwise, do nothing or output debugging text #if DEBUG >= 5 fprintf(stderr, "Spawned new process %i for socket %i\n", (int)myid, S.getSocket()); #endif } } } //while connected server_socket.close(); return 0; } //main
/// Main Connector_RTMP function int Connector_RTMP::Connector_RTMP(Socket::Connection conn){ Socket = conn; Socket.setBlocking(false); FLV::Tag tag, init_tag; DTSC::Stream Strm; while (!Socket.Received().available(1537) && Socket.connected()){Socket.spool(); Util::sleep(5);} RTMPStream::handshake_in = Socket.Received().remove(1537); RTMPStream::rec_cnt += 1537; if (RTMPStream::doHandshake()){ Socket.SendNow(RTMPStream::handshake_out); while (!Socket.Received().available(1536) && Socket.connected()){Socket.spool(); Util::sleep(5);} Socket.Received().remove(1536); RTMPStream::rec_cnt += 1536; #if DEBUG >= 4 fprintf(stderr, "Handshake succcess!\n"); #endif }else{ #if DEBUG >= 1 fprintf(stderr, "Handshake fail!\n"); #endif return 0; } unsigned int lastStats = 0; bool firsttime = true; while (Socket.connected()){ if (Socket.spool() || firsttime){ parseChunk(Socket.Received()); firsttime = false; }else{ Util::sleep(1);//sleep 1ms to prevent high CPU usage } if (ready4data){ if (!inited){ //we are ready, connect the socket! SS = Util::Stream::getStream(streamname); if (!SS.connected()){ #if DEBUG >= 1 fprintf(stderr, "Could not connect to server!\n"); #endif Socket.close();//disconnect user break; } SS.setBlocking(false); #if DEBUG >= 3 fprintf(stderr, "Everything connected, starting to send video data...\n"); #endif SS.SendNow("p\n"); inited = true; } if (inited && !nostats){ long long int now = Util::epoch(); if (now != lastStats){ lastStats = now; SS.SendNow(Socket.getStats("RTMP").c_str()); } } if (SS.spool()){ while (Strm.parsePacket(SS.Received())){ if (play_trans != -1){ //send a status reply AMF::Object amfreply("container", AMF::AMF0_DDV_CONTAINER); amfreply.addContent(AMF::Object("", "onStatus"));//status reply amfreply.addContent(AMF::Object("", (double)play_trans));//same transaction ID amfreply.addContent(AMF::Object("", (double)0, AMF::AMF0_NULL));//null - command info amfreply.addContent(AMF::Object(""));//info amfreply.getContentP(3)->addContent(AMF::Object("level", "status")); amfreply.getContentP(3)->addContent(AMF::Object("code", "NetStream.Play.Reset")); amfreply.getContentP(3)->addContent(AMF::Object("description", "Playing and resetting...")); amfreply.getContentP(3)->addContent(AMF::Object("details", "DDV")); amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1337)); sendCommand(amfreply, play_msgtype, play_streamid); //send streamisrecorded if stream, well, is recorded. if (Strm.metadata.isMember("length") && Strm.metadata["length"].asInt() > 0){ Socket.Send(RTMPStream::SendUSR(4, 1));//send UCM StreamIsRecorded (4), stream 1 } //send streambegin Socket.Send(RTMPStream::SendUSR(0, 1));//send UCM StreamBegin (0), stream 1 //and more reply amfreply = AMF::Object("container", AMF::AMF0_DDV_CONTAINER); amfreply.addContent(AMF::Object("", "onStatus"));//status reply amfreply.addContent(AMF::Object("", (double)play_trans));//same transaction ID amfreply.addContent(AMF::Object("", (double)0, AMF::AMF0_NULL));//null - command info amfreply.addContent(AMF::Object(""));//info amfreply.getContentP(3)->addContent(AMF::Object("level", "status")); amfreply.getContentP(3)->addContent(AMF::Object("code", "NetStream.Play.Start")); amfreply.getContentP(3)->addContent(AMF::Object("description", "Playing!")); amfreply.getContentP(3)->addContent(AMF::Object("details", "DDV")); amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1337)); sendCommand(amfreply, play_msgtype, play_streamid); RTMPStream::chunk_snd_max = 102400;//100KiB Socket.Send(RTMPStream::SendCTL(1, RTMPStream::chunk_snd_max));//send chunk size max (msg 1) //send dunno? Socket.Send(RTMPStream::SendUSR(32, 1));//send UCM no clue?, stream 1 play_trans = -1; } //sent init data if needed if (!stream_inited){ init_tag.DTSCMetaInit(Strm); Socket.SendNow(RTMPStream::SendMedia(init_tag)); if (Strm.metadata.isMember("audio") && Strm.metadata["audio"].isMember("init")){ init_tag.DTSCAudioInit(Strm); Socket.SendNow(RTMPStream::SendMedia(init_tag)); } if (Strm.metadata.isMember("video") && Strm.metadata["video"].isMember("init")){ init_tag.DTSCVideoInit(Strm); Socket.SendNow(RTMPStream::SendMedia(init_tag)); } stream_inited = true; } //sent a tag tag.DTSCLoader(Strm); Socket.SendNow(RTMPStream::SendMedia(tag)); #if DEBUG >= 8 fprintf(stderr, "Sent tag to %i: [%u] %s\n", Socket.getSocket(), tag.tagTime(), tag.tagType().c_str()); #endif } } } } Socket.close(); SS.SendNow(Socket.getStats("RTMP").c_str()); SS.close(); #if DEBUG >= 1 if (FLV::Parse_Error){fprintf(stderr, "FLV Parse Error: %s\n", FLV::Error_Str.c_str());} fprintf(stderr, "User %i disconnected.\n", conn.getSocket()); if (inited){ fprintf(stderr, "Status was: inited\n"); }else{ if (ready4data){ fprintf(stderr, "Status was: ready4data\n"); }else{ fprintf(stderr, "Status was: connected\n"); } } #endif return 0; }//Connector_RTMP
///\brief Main function for the RTMP Connector ///\param conn A socket describing the connection the client. ///\return The exit code of the connector. int rtmpConnector(Socket::Connection conn){ Socket = conn; Socket.setBlocking(false); FLV::Tag tag, init_tag; DTSC::Stream Strm; while ( !Socket.Received().available(1537) && Socket.connected()){ Socket.spool(); Util::sleep(5); } RTMPStream::handshake_in = Socket.Received().remove(1537); RTMPStream::rec_cnt += 1537; if (RTMPStream::doHandshake()){ Socket.SendNow(RTMPStream::handshake_out); while ( !Socket.Received().available(1536) && Socket.connected()){ Socket.spool(); Util::sleep(5); } Socket.Received().remove(1536); RTMPStream::rec_cnt += 1536; #if DEBUG >= 5 fprintf(stderr, "Handshake succcess!\n"); #endif }else{ #if DEBUG >= 5 fprintf(stderr, "Handshake fail!\n"); #endif return 0; } unsigned int lastStats = 0; bool firsttime = true; while (Socket.connected()){ if (Socket.spool() || firsttime){ parseChunk(Socket.Received()); firsttime = false; }else{ Util::sleep(1); //sleep 1ms to prevent high CPU usage } if (ready4data){ if ( !inited){ //we are ready, connect the socket! ss = Util::Stream::getStream(streamName); if ( !ss.connected()){ #if DEBUG >= 1 fprintf(stderr, "Could not connect to server!\n"); #endif Socket.close(); //disconnect user break; } ss.setBlocking(false); Strm.waitForMeta(ss); //find first audio and video tracks for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ if (videoID == -1 && objIt->second["type"].asStringRef() == "video"){ videoID = objIt->second["trackid"].asInt(); } if (audioID == -1 && objIt->second["type"].asStringRef() == "audio"){ audioID = objIt->second["trackid"].asInt(); } } //select the tracks and play std::stringstream cmd; cmd << "t"; if (videoID != -1){ cmd << " " << videoID; } if (audioID != -1){ cmd << " " << audioID; } cmd << "\np\n"; ss.SendNow(cmd.str().c_str()); inited = true; } if (inited && !noStats){ long long int now = Util::epoch(); if (now != lastStats){ lastStats = now; ss.SendNow(Socket.getStats("RTMP")); } } if (ss.spool()){ while (Strm.parsePacket(ss.Received())){ if (playTransaction != -1){ //send a status reply AMF::Object amfreply("container", AMF::AMF0_DDV_CONTAINER); amfreply.addContent(AMF::Object("", "onStatus")); //status reply amfreply.addContent(AMF::Object("", (double)playTransaction)); //same transaction ID amfreply.addContent(AMF::Object("", (double)0, AMF::AMF0_NULL)); //null - command info amfreply.addContent(AMF::Object("")); //info amfreply.getContentP(3)->addContent(AMF::Object("level", "status")); amfreply.getContentP(3)->addContent(AMF::Object("code", "NetStream.Play.Reset")); amfreply.getContentP(3)->addContent(AMF::Object("description", "Playing and resetting...")); amfreply.getContentP(3)->addContent(AMF::Object("details", "DDV")); amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1337)); sendCommand(amfreply, playMessageType, playStreamId); //send streamisrecorded if stream, well, is recorded. if (Strm.metadata.isMember("length") && Strm.metadata["length"].asInt() > 0){ Socket.Send(RTMPStream::SendUSR(4, 1)); //send UCM StreamIsRecorded (4), stream 1 } //send streambegin Socket.Send(RTMPStream::SendUSR(0, 1)); //send UCM StreamBegin (0), stream 1 //and more reply amfreply = AMF::Object("container", AMF::AMF0_DDV_CONTAINER); amfreply.addContent(AMF::Object("", "onStatus")); //status reply amfreply.addContent(AMF::Object("", (double)playTransaction)); //same transaction ID amfreply.addContent(AMF::Object("", (double)0, AMF::AMF0_NULL)); //null - command info amfreply.addContent(AMF::Object("")); //info amfreply.getContentP(3)->addContent(AMF::Object("level", "status")); amfreply.getContentP(3)->addContent(AMF::Object("code", "NetStream.Play.Start")); amfreply.getContentP(3)->addContent(AMF::Object("description", "Playing!")); amfreply.getContentP(3)->addContent(AMF::Object("details", "DDV")); amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1337)); sendCommand(amfreply, playMessageType, playStreamId); RTMPStream::chunk_snd_max = 102400; //100KiB Socket.Send(RTMPStream::SendCTL(1, RTMPStream::chunk_snd_max)); //send chunk size max (msg 1) //send dunno? Socket.Send(RTMPStream::SendUSR(32, 1)); //send UCM no clue?, stream 1 playTransaction = -1; } //sent init data if needed if ( !streamInited){ init_tag.DTSCMetaInit(Strm, Strm.getTrackById(videoID), Strm.getTrackById(audioID)); Socket.SendNow(RTMPStream::SendMedia(init_tag)); if (audioID != -1 && Strm.getTrackById(audioID).isMember("init")){ init_tag.DTSCAudioInit(Strm.getTrackById(audioID)); Socket.SendNow(RTMPStream::SendMedia(init_tag)); } if (videoID != -1 && Strm.getTrackById(videoID).isMember("init")){ init_tag.DTSCVideoInit(Strm.getTrackById(videoID)); Socket.SendNow(RTMPStream::SendMedia(init_tag)); } streamInited = true; } //sent a tag tag.DTSCLoader(Strm); Socket.SendNow(RTMPStream::SendMedia(tag)); #if DEBUG >= 8 fprintf(stderr, "Sent tag to %i: [%u] %s\n", Socket.getSocket(), tag.tagTime(), tag.tagType().c_str()); #endif } } } } Socket.close(); ss.SendNow(Socket.getStats("RTMP").c_str()); ss.close(); return 0; } //Connector_RTMP