int SrsPlayEdge::on_ingest_play()
{
    int ret = ERROR_SUCCESS;
    
    // when already connected(for instance, reconnect for error), ignore.
    if (state == SrsEdgeStateIngestConnected) {
        return ret;
    }
    
    srs_assert(state == SrsEdgeStatePlay);
    
    SrsEdgeState pstate = state;
    state = SrsEdgeStateIngestConnected;
    srs_trace("edge change from %d to state %d (ingest connected).", pstate, state);
    
    return ret;
}
Exemplo n.º 2
0
int SrsEdgeIngester::connect_server()
{
    int ret = ERROR_SUCCESS;
    
    // reopen
    close_underlayer_socket();
    
    SrsConfDirective* conf = _srs_config->get_vhost_edge_origin(_req->vhost);
    srs_assert(conf);
    
    // select the origin.
    std::string server = conf->args.at(origin_index % conf->args.size());
    origin_index = (origin_index + 1) % conf->args.size();
    
    std::string s_port = SRS_CONSTS_RTMP_DEFAULT_PORT;
    int port = ::atoi(SRS_CONSTS_RTMP_DEFAULT_PORT);
    size_t pos = server.find(":");
    if (pos != std::string::npos) {
        s_port = server.substr(pos + 1);
        server = server.substr(0, pos);
        port = ::atoi(s_port.c_str());
    }
    
    // open socket.
    int64_t timeout = SRS_EDGE_INGESTER_TIMEOUT_US;
    if ((ret = srs_socket_connect(server, port, timeout, &stfd)) != ERROR_SUCCESS) {
        srs_warn("edge pull failed, stream=%s, tcUrl=%s to server=%s, port=%d, timeout=%"PRId64", ret=%d",
            _req->stream.c_str(), _req->tcUrl.c_str(), server.c_str(), port, timeout, ret);
        return ret;
    }
    
    srs_freep(client);
    srs_freep(io);
    
    srs_assert(stfd);
    io = new SrsStSocket(stfd);
    client = new SrsRtmpClient(io);
    
    kbps->set_io(io, io);
    
    srs_trace("edge pull connected, can_publish=%d, url=%s/%s, server=%s:%d",
        _source->can_publish(), _req->tcUrl.c_str(), _req->stream.c_str(), server.c_str(), port);
    
    return ret;
}
Exemplo n.º 3
0
int SrsEdgeIngester::ingest()
{
    int ret = ERROR_SUCCESS;
    
    client->set_recv_timeout(SRS_EDGE_INGESTER_TIMEOUT_US);
    
    SrsPithyPrint pithy_print(SRS_CONSTS_STAGE_EDGE);

    while (pthread->can_loop()) {
        // switch to other st-threads.
        st_usleep(0);
        
        pithy_print.elapse();
        
        // pithy print
        if (pithy_print.can_print()) {
            kbps->sample();
            srs_trace("<- "SRS_CONSTS_LOG_EDGE_PLAY
                " time=%"PRId64", okbps=%d,%d,%d, ikbps=%d,%d,%d", 
                pithy_print.age(),
                kbps->get_send_kbps(), kbps->get_send_kbps_30s(), kbps->get_send_kbps_5m(),
                kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m());
        }

        // read from client.
        SrsMessage* msg = NULL;
        if ((ret = client->recv_message(&msg)) != ERROR_SUCCESS) {
            if (!srs_is_client_gracefully_close(ret)) {
                srs_error("pull origin server message failed. ret=%d", ret);
            }
            return ret;
        }
        srs_verbose("edge loop recv message. ret=%d", ret);
        
        srs_assert(msg);
        SrsAutoFree(SrsMessage, msg);
        
        if ((ret = process_publish_message(msg)) != ERROR_SUCCESS) {
            return ret;
        }
    }
    
    return ret;
}
Exemplo n.º 4
0
void srs_random_generate(char* bytes, int size)
{
    static bool _random_initialized = false;
    if (!_random_initialized) {
        srand(0);
        _random_initialized = true;
        srs_trace("srand initialized the random.");
    }
    
    static char cdata[]  = { 
        0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x72, 0x74, 0x6d, 0x70, 0x2d, 0x73, 0x65, 
        0x72, 0x76, 0x65, 0x72, 0x2d, 0x77, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x2d, 0x77, 0x69, 
        0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x40, 0x31, 0x32, 0x36, 
        0x2e, 0x63, 0x6f, 0x6d
    };
    for (int i = 0; i < size; i++) {
        bytes[i] = cdata[rand() % (sizeof(cdata) - 1)];
    }
}
int SrsSignalManager::start()
{
    int ret = ERROR_SUCCESS;
    
    /**
    * Note that if multiple processes are used (see below), 
    * the signal pipe should be initialized after the fork(2) call 
    * so that each process has its own private pipe.
    */
    struct sigaction sa;
    
    /* Create signal pipe */
    if (pipe(sig_pipe) < 0) {
        ret = ERROR_SYSTEM_CREATE_PIPE;
        srs_error("create signal manager pipe failed. ret=%d", ret);
        return ret;
    }
    
    /* Install sig_catcher() as a signal handler */
    sa.sa_handler = SrsSignalManager::sig_catcher;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGNAL_RELOAD, &sa, NULL);
    
    sa.sa_handler = SrsSignalManager::sig_catcher;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);
    
    sa.sa_handler = SrsSignalManager::sig_catcher;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);
    
    sa.sa_handler = SrsSignalManager::sig_catcher;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR2, &sa, NULL);
    
    srs_trace("signal installed");
    
    return pthread->start();
}
Exemplo n.º 6
0
int SrsServer::cycle()
{
    int ret = ERROR_SUCCESS;
    
    // the deamon thread, update the time cache
    while (true) {
        st_usleep(SRS_TIME_RESOLUTION_MS * 1000);
        srs_update_system_time_ms();
        
// for gperf heap checker,
// @see: research/gperftools/heap-checker/heap_checker.cc
// if user interrupt the program, exit to check mem leak.
// but, if gperf, use reload to ensure main return normally,
// because directly exit will cause core-dump.
#ifdef SRS_GPERF_MC
        if (signal_gmc_stop) {
            break;
        }
#endif
        
        if (signal_reload) {
            signal_reload = false;
            srs_info("get signal reload, to reload the config.");
            
            if ((ret = _srs_config->reload()) != ERROR_SUCCESS) {
                srs_error("reload config failed. ret=%d", ret);
                return ret;
            }
            srs_trace("reload config success.");
        }
    }

#ifdef SRS_INGEST
    ingester->stop();
#endif
    
    return ret;
}
int srs_rtmp_expect_message(SrsProtocol* protocol, SrsCommonMessage** pmsg, T** ppacket)
{
    *pmsg = NULL;
    *ppacket = NULL;
    
    int ret = ERROR_SUCCESS;
    
    while (true) {
        SrsCommonMessage* msg = NULL;
        if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) {
            srs_error("recv message failed. ret=%d", ret);
            return ret;
        }
        srs_verbose("recv message success.");
        
        if ((ret = msg->decode_packet(protocol)) != ERROR_SUCCESS) {
            delete msg;
            srs_error("decode message failed. ret=%d", ret);
            return ret;
        }
        
        T* pkt = dynamic_cast<T*>(msg->get_packet());
        if (!pkt) {
            delete msg;
            srs_trace("drop message(type=%d, size=%d, time=%"PRId64", sid=%d).", 
                msg->header.message_type, msg->header.payload_length,
                msg->header.timestamp, msg->header.stream_id);
            continue;
        }
        
        *pmsg = msg;
        *ppacket = pkt;
        break;
    }
    
    return ret;
}
Exemplo n.º 8
0
int SrsServer::do_cycle()
{
    int ret = ERROR_SUCCESS;
    
    // find the max loop
    int max = srs_max(0, SRS_SYS_TIME_RESOLUTION_MS_TIMES);
    max = srs_max(max, SRS_SYS_RUSAGE_RESOLUTION_TIMES);
    max = srs_max(max, SRS_SYS_CPU_STAT_RESOLUTION_TIMES);
    max = srs_max(max, SRS_SYS_DISK_STAT_RESOLUTION_TIMES);
    max = srs_max(max, SRS_SYS_MEMINFO_RESOLUTION_TIMES);
    max = srs_max(max, SRS_SYS_PLATFORM_INFO_RESOLUTION_TIMES);
    max = srs_max(max, SRS_SYS_NETWORK_DEVICE_RESOLUTION_TIMES);
    max = srs_max(max, SRS_SYS_NETWORK_RTMP_SERVER_RESOLUTION_TIMES);
    
    // the deamon thread, update the time cache
    while (true) {
        // the interval in config.
        int heartbeat_max_resolution = (int)(_srs_config->get_heartbeat_interval() / 100);
        
        // dynamic fetch the max.
        int __max = max;
        __max = srs_max(__max, heartbeat_max_resolution);
        
        for (int i = 0; i < __max; i++) {
            st_usleep(SRS_SYS_CYCLE_INTERVAL * 1000);
        
// for gperf heap checker,
// @see: research/gperftools/heap-checker/heap_checker.cc
// if user interrupt the program, exit to check mem leak.
// but, if gperf, use reload to ensure main return normally,
// because directly exit will cause core-dump.
#ifdef SRS_AUTO_GPERF_MC
            if (signal_gmc_stop) {
                srs_warn("gmc got singal to stop server.");
                return ret;
            }
#endif
        
            if (signal_reload) {
                signal_reload = false;
                srs_info("get signal reload, to reload the config.");
                
                if ((ret = _srs_config->reload()) != ERROR_SUCCESS) {
                    srs_error("reload config failed. ret=%d", ret);
                    return ret;
                }
                srs_trace("reload config success.");
            }
            
            // update the cache time or rusage.
            if ((i % SRS_SYS_TIME_RESOLUTION_MS_TIMES) == 0) {
                srs_info("update current time cache.");
                srs_update_system_time_ms();
            }
            if ((i % SRS_SYS_RUSAGE_RESOLUTION_TIMES) == 0) {
                srs_info("update resource info, rss.");
                srs_update_system_rusage();
            }
            if ((i % SRS_SYS_CPU_STAT_RESOLUTION_TIMES) == 0) {
                srs_info("update cpu info, cpu usage.");
                srs_update_proc_stat();
            }
            if ((i % SRS_SYS_DISK_STAT_RESOLUTION_TIMES) == 0) {
                srs_info("update disk info, disk iops.");
                srs_update_disk_stat();
            }
            if ((i % SRS_SYS_MEMINFO_RESOLUTION_TIMES) == 0) {
                srs_info("update memory info, usage/free.");
                srs_update_meminfo();
            }
            if ((i % SRS_SYS_PLATFORM_INFO_RESOLUTION_TIMES) == 0) {
                srs_info("update platform info, uptime/load.");
                srs_update_platform_info();
            }
            if ((i % SRS_SYS_NETWORK_DEVICE_RESOLUTION_TIMES) == 0) {
                srs_info("update network devices info.");
                srs_update_network_devices();
            }
            if ((i % SRS_SYS_NETWORK_RTMP_SERVER_RESOLUTION_TIMES) == 0) {
                srs_info("update network rtmp server info.");
                resample_kbps(NULL);
                srs_update_rtmp_server((int)conns.size(), kbps);
            }
#ifdef SRS_AUTO_HTTP_PARSER
            if (_srs_config->get_heartbeat_enabled()) {
                if ((i % heartbeat_max_resolution) == 0) {
                    srs_info("do http heartbeat, for internal server to report.");
                    http_heartbeat->heartbeat();
                }
            }
#endif
            srs_info("server main thread loop");
        }
    }

    return ret;
}
int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata)
{
	int ret = ERROR_SUCCESS;
	
#ifdef SRS_HLS
	if ((ret = hls->on_meta_data(metadata)) != ERROR_SUCCESS) {
		srs_error("hls process onMetaData message failed. ret=%d", ret);
		return ret;
	}
#endif
	
	metadata->metadata->set("server", new SrsAmf0String(
		RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));
	
	SrsAmf0Any* prop = NULL;
	if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) {
		if (prop->is_number()) {
			sample_rate = (int)(srs_amf0_convert<SrsAmf0Number>(prop)->value);
		}
	}
	if ((prop = metadata->metadata->get_property("framerate")) != NULL) {
		if (prop->is_number()) {
			frame_rate = (int)(srs_amf0_convert<SrsAmf0Number>(prop)->value);
		}
	}
	
	// encode the metadata to payload
	int size = metadata->get_payload_length();
	if (size <= 0) {
		srs_warn("ignore the invalid metadata. size=%d", size);
		return ret;
	}
	srs_verbose("get metadata size success.");
	
	char* payload = new char[size];
	memset(payload, 0, size);
	if ((ret = metadata->encode(size, payload)) != ERROR_SUCCESS) {
		srs_error("encode metadata error. ret=%d", ret);
		srs_freepa(payload);
		return ret;
	}
	srs_verbose("encode metadata success.");
	
	// create a shared ptr message.
	srs_freep(cache_metadata);
	cache_metadata = new SrsSharedPtrMessage();
	
	// dump message to shared ptr message.
	if ((ret = cache_metadata->initialize(msg, payload, size)) != ERROR_SUCCESS) {
		srs_error("initialize the cache metadata failed. ret=%d", ret);
		return ret;
	}
	srs_verbose("initialize shared ptr metadata success.");
	
	// copy to all consumer
	if (true) {
		std::vector<SrsConsumer*>::iterator it;
		for (it = consumers.begin(); it != consumers.end(); ++it) {
			SrsConsumer* consumer = *it;
			if ((ret = consumer->enqueue(cache_metadata->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
				srs_error("dispatch the metadata failed. ret=%d", ret);
				return ret;
			}
		}
		srs_trace("dispatch metadata success.");
	}
	
	// copy to all forwarders
	if (true) {
		std::vector<SrsForwarder*>::iterator it;
		for (it = forwarders.begin(); it != forwarders.end(); ++it) {
			SrsForwarder* forwarder = *it;
			if ((ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) {
				srs_error("forwarder process onMetaData message failed. ret=%d", ret);
				return ret;
			}
		}
	}
	
	return ret;
}
Exemplo n.º 10
0
int main(int argc, char** argv)
{
    srs_trace("tcp server to send random data to clients.");
    if (argc <= 2) {
        srs_trace("Usage: %s <port> <packet_bytes>", argv[0]);
        srs_trace("   port: the listen port.");
        srs_trace("   packet_bytes: the bytes for packet to send.");
        srs_trace("For example:");
        srs_trace("   %s %d %d", argv[0], 1990, 4096);
        return -1;
    }
    
    int listen_port = ::atoi(argv[1]);
    int packet_bytes = ::atoi(argv[2]);
    srs_trace("listen_port is %d", listen_port);
    srs_trace("packet_bytes is %d", packet_bytes);
    
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        srs_trace("create socket failed.");
        return -1;
    }
    
    int reuse_socket = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
        srs_trace("setsockopt reuse-addr error.");
        return -1;
    }
    srs_trace("setsockopt reuse-addr success. fd=%d", fd);
    
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(listen_port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (::bind(fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
        srs_trace("bind socket error.");
        return -1;
    }
    srs_trace("bind socket success. fd=%d", fd);
    
    if (::listen(fd, 10) == -1) {
        srs_trace("listen socket error.");
        return -1;
    }
    srs_trace("listen socket success. fd=%d", fd);
    
    // get the sockoptions
    int sock_send_buffer = 0;
    socklen_t nb_sock_send_buffer = sizeof(int);
    if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sock_send_buffer, &nb_sock_send_buffer) < 0) {
        srs_trace("get sockopt failed.");
        return -1;
    }
    srs_trace("SO_SNDBUF=%d", sock_send_buffer);
    
    for (;;) {
        int conn = accept(fd, NULL, NULL);
        if (conn < 0) {
            srs_trace("accept socket error.");
            return -1;
        }
        srs_trace("accept socket ok, conn=%d", conn);
        
        char b[4096];
        for (;;) {
            ssize_t nb_send = send(conn, b, sizeof(b), 0);
            if (nb_send != sizeof(b)) {
                srs_trace("send bytes to socket error.");
                ::close(conn);
                break;
            }
        }
    }
    
    return 0;
}
Exemplo n.º 11
0
void SrsListener::on_thread_start()
{
    srs_trace("listen cycle start, port=%d, type=%d, fd=%d", port, type, fd);
}
Exemplo n.º 12
0
int SrsServer::acquire_pid_file()
{
    int ret = ERROR_SUCCESS;
    
    std::string pid_file = _srs_config->get_pid_file();
    
    // -rw-r--r-- 
    // 644
    int mode = S_IRUSR | S_IWUSR |  S_IRGRP | S_IROTH;
    
    int fd;
    // open pid file
    if ((fd = ::open(pid_file.c_str(), O_WRONLY | O_CREAT, mode)) < 0) {
        ret = ERROR_SYSTEM_PID_ACQUIRE;
        srs_error("open pid file %s error, ret=%#x", pid_file.c_str(), ret);
        return ret;
    }
    
    // require write lock
    flock lock;

    lock.l_type = F_WRLCK; // F_RDLCK, F_WRLCK, F_UNLCK
    lock.l_start = 0; // type offset, relative to l_whence
    lock.l_whence = SEEK_SET;  // SEEK_SET, SEEK_CUR, SEEK_END
    lock.l_len = 0;
    
    if (fcntl(fd, F_SETLK, &lock) < 0) {
        if(errno == EACCES || errno == EAGAIN) {
            ret = ERROR_SYSTEM_PID_ALREADY_RUNNING;
            srs_error("srs is already running! ret=%#x", ret);
            return ret;
        }
        
        ret = ERROR_SYSTEM_PID_LOCK;
        srs_error("require lock for file %s error! ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    // truncate file
    if (ftruncate(fd, 0) < 0) {
        ret = ERROR_SYSTEM_PID_TRUNCATE_FILE;
        srs_error("truncate pid file %s error! ret=%#x", pid_file.c_str(), ret);
        return ret;
    }

    int pid = (int)getpid();
    
    // write the pid
    char buf[512];
    snprintf(buf, sizeof(buf), "%d", pid);
    if (write(fd, buf, strlen(buf)) != (int)strlen(buf)) {
        ret = ERROR_SYSTEM_PID_WRITE_FILE;
        srs_error("write our pid error! pid=%d file=%s ret=%#x", pid, pid_file.c_str(), ret);
        return ret;
    }

    // auto close when fork child process.
    int val;
    if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
        ret = ERROR_SYSTEM_PID_GET_FILE_INFO;
        srs_error("fnctl F_GETFD error! file=%s ret=%#x", pid_file.c_str(), ret);
        return ret;
    }
    val |= FD_CLOEXEC;
    if (fcntl(fd, F_SETFD, val) < 0) {
        ret = ERROR_SYSTEM_PID_SET_FILE_INFO;
        srs_error("fcntl F_SETFD error! file=%s ret=%#x", pid_file.c_str(), ret);
        return ret;
    }
    
    srs_trace("write pid=%d to %s success!", pid, pid_file.c_str());
    
    return ret;
}
int SrsForwarder::forward()
{
    int ret = ERROR_SUCCESS;
    
    client->set_recv_timeout(SRS_PULSE_TIMEOUT_US);
    
    SrsPithyPrint pithy_print(SRS_STAGE_FORWARDER);

    SrsSharedPtrMessageArray msgs(SYS_MAX_FORWARD_SEND_MSGS);
    
    while (pthread->can_loop()) {
        // switch to other st-threads.
        st_usleep(0);

        pithy_print.elapse();

        // read from client.
        if (true) {
            SrsMessage* msg = NULL;
            ret = client->recv_message(&msg);
            
            srs_verbose("play loop recv message. ret=%d", ret);
            if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
                srs_error("recv server control message failed. ret=%d", ret);
                return ret;
            }
            
            srs_freep(msg);
        }
        
        // forward all messages.
        int count = 0;
        if ((ret = queue->dump_packets(msgs.size, msgs.msgs, count)) != ERROR_SUCCESS) {
            srs_error("get message to forward failed. ret=%d", ret);
            return ret;
        }
        
        // pithy print
        if (pithy_print.can_print()) {
            kbps->sample();
            srs_trace("-> "SRS_LOG_ID_FOWARDER
                " time=%"PRId64", msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", 
                pithy_print.age(), count,
                kbps->get_send_kbps(), kbps->get_send_kbps_30s(), kbps->get_send_kbps_5m(),
                kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m());
        }
        
        // ignore when no messages.
        if (count <= 0) {
            srs_verbose("no packets to forward.");
            continue;
        }
    
        // all msgs to forward.
        // @remark, becareful, all msgs must be free explicitly,
        //      free by send_and_free_message or srs_freep.
        for (int i = 0; i < count; i++) {
            SrsSharedPtrMessage* msg = msgs.msgs[i];
            
            srs_assert(msg);
            msgs.msgs[i] = NULL;
            
            if ((ret = client->send_and_free_message(msg, stream_id)) != ERROR_SUCCESS) {
                srs_error("forwarder send message to server failed. ret=%d", ret);
                return ret;
            }
        }
    }
    
    return ret;
}
int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
{
    int ret = ERROR_SUCCESS;
    
    // forward app
    app = req->app;
    
    stream_name = req->stream;
    server = forward_server;
    std::string s_port = RTMP_DEFAULT_PORT;
    port = ::atoi(RTMP_DEFAULT_PORT);
    
    // TODO: FIXME: parse complex params
    size_t pos = forward_server.find(":");
    if (pos != std::string::npos) {
        s_port = forward_server.substr(pos + 1);
        server = forward_server.substr(0, pos);
    }
    // discovery vhost
    std::string vhost = req->vhost;
    srs_vhost_resolve(vhost, s_port);
    port = ::atoi(s_port.c_str());
    
    // generate tcUrl
    tc_url = "rtmp://";
    if (vhost == RTMP_VHOST_DEFAULT) {
        tc_url += forward_server;
    } else {
        tc_url += vhost;
    }
    tc_url += "/";
    tc_url += req->app;
    
    // dead loop check
    std::string source_ep = "rtmp://";
    source_ep += req->host;
    source_ep += ":";
    source_ep += req->port;
    source_ep += "?vhost=";
    source_ep += req->vhost;
    
    std::string dest_ep = "rtmp://";
    if (forward_server == "127.0.0.1") {
        dest_ep += req->host;
    } else {
        dest_ep += forward_server;
    }
    dest_ep += ":";
    dest_ep += s_port;
    dest_ep += "?vhost=";
    dest_ep += vhost;
    
    if (source_ep == dest_ep) {
        ret = ERROR_SYSTEM_FORWARD_LOOP;
        srs_warn("forward loop detected. src=%s, dest=%s, ret=%d", 
            source_ep.c_str(), dest_ep.c_str(), ret);
        return ret;
    }
    srs_trace("start forward %s to %s, tcUrl=%s, stream=%s", 
        source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), 
        stream_name.c_str());
    
    if ((ret = pthread->start()) != ERROR_SUCCESS) {
        srs_error("start srs thread failed. ret=%d", ret);
        return ret;
    }
    srs_trace("forward thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id());
    
    return ret;
}
Exemplo n.º 15
0
/**
* main entrance.
*/
int main(int argc, char** argv) 
{
    int ret = ERROR_SUCCESS;

    // TODO: support both little and big endian.
    srs_assert(srs_is_little_endian());

#ifdef SRS_AUTO_GPERF_MP
    HeapProfilerStart("gperf.srs.gmp");
#endif
#ifdef SRS_AUTO_GPERF_CP
    ProfilerStart("gperf.srs.gcp");
#endif

#if defined(SRS_AUTO_GPERF_MC) && defined(SRS_AUTO_GPERF_MP)
    srs_error("option --with-gmc confict with --with-gmp, "
        "@see: http://google-perftools.googlecode.com/svn/trunk/doc/heap_checker.html\n"
        "Note that since the heap-checker uses the heap-profiling framework internally, "
        "it is not possible to run both the heap-checker and heap profiler at the same time");
    return -1;
#endif
    
    // never use srs log(srs_trace, srs_error, etc) before config parse the option,
    // which will load the log config and apply it.
    if ((ret = _srs_config->parse_options(argc, argv)) != ERROR_SUCCESS) {
        return ret;
    }
    
    // config parsed, initialize log.
    if ((ret = _srs_log->initialize()) != ERROR_SUCCESS) {
        return ret;
    }

    // we check the config when the log initialized.
    if ((ret = _srs_config->check_config()) != ERROR_SUCCESS) {
        return ret;
    }
    
    srs_trace("srs(simple-rtmp-server) "RTMP_SIG_SRS_VERSION);
    srs_trace("license: "RTMP_SIG_SRS_LICENSE);
    srs_trace("authors: "RTMP_SIG_SRS_PRIMARY_AUTHROS);
    srs_trace("contributors: "SRS_AUTO_CONSTRIBUTORS);
    srs_trace("uname: "SRS_AUTO_UNAME);
    srs_trace("build: %s, %s", SRS_AUTO_BUILD_DATE, srs_is_little_endian()? "little-endian":"big-endian");
    srs_trace("configure: "SRS_AUTO_USER_CONFIGURE);
    srs_trace("features: "SRS_AUTO_CONFIGURE);
#ifdef SRS_AUTO_ARM_UBUNTU12
    srs_trace("arm tool chain: "SRS_AUTO_EMBEDED_TOOL_CHAIN);
#endif
    srs_trace("conf: %s, limit: %d", _srs_config->config().c_str(), _srs_config->get_max_connections());
    
    // features
    show_macro_features();
    check_macro_features();
    
    /**
    * we do nothing in the constructor of server,
    * and use initialize to create members, set hooks for instance the reload handler,
    * all initialize will done in this stage.
    */
    if ((ret = _srs_server->initialize()) != ERROR_SUCCESS) {
        return ret;
    }
    
    return run();
}
Exemplo n.º 16
0
/**
* show the features by macro, the actual macro values.
*/
void show_macro_features()
{
#ifdef SRS_AUTO_SSL
    srs_trace("check feature rtmp handshake: on");
#else
    srs_warn("check feature rtmp handshake: off");
#endif

#ifdef SRS_AUTO_HLS
    srs_trace("check feature hls: on");
#else
    srs_warn("check feature hls: off");
#endif

#ifdef SRS_AUTO_HTTP_CALLBACK
    srs_trace("check feature http callback: on");
#else
    srs_warn("check feature http callback: off");
#endif

#ifdef SRS_AUTO_HTTP_API
    srs_trace("check feature http api: on");
#else
    srs_warn("check feature http api: off");
#endif

#ifdef SRS_AUTO_HTTP_SERVER
    srs_trace("check feature http server: on");
#else
    srs_warn("check feature http server: off");
#endif

#ifdef SRS_AUTO_HTTP_PARSER
    srs_trace("check feature http parser: on");
#else
    srs_warn("check feature http parser: off");
#endif

#ifdef SRS_AUTO_DVR
    srs_trace("check feature dvr: on");
#else
    srs_warn("check feature dvr: off");
#endif

#ifdef SRS_AUTO_TRANSCODE
    srs_trace("check feature transcode: on");
#else
    srs_warn("check feature transcode: off");
#endif

#ifdef SRS_AUTO_INGEST
    srs_trace("check feature ingest: on");
#else
    srs_warn("check feature ingest: off");
#endif

#ifdef SRS_AUTO_STAT
    srs_trace("check feature system stat: on");
#else
    srs_warn("check feature system stat: off");
#endif

#ifdef SRS_AUTO_NGINX
    srs_trace("check feature compile nginx: on");
#else
    srs_warn("check feature compile nginx: off");
#endif

#ifdef SRS_AUTO_FFMPEG_TOOL
    srs_trace("check feature compile ffmpeg: on");
#else
    srs_warn("check feature compile ffmpeg: off");
#endif
}
int SrsSource::on_video(SrsCommonMessage* video)
{
	int ret = ERROR_SUCCESS;
	
	SrsSharedPtrMessage* msg = new SrsSharedPtrMessage();
	SrsAutoFree(SrsSharedPtrMessage, msg, false);
	if ((ret = msg->initialize(video)) != ERROR_SUCCESS) {
		srs_error("initialize the video failed. ret=%d", ret);
		return ret;
	}
	srs_verbose("initialize shared ptr video success.");
	
#ifdef SRS_HLS
	if ((ret = hls->on_video(msg->copy())) != ERROR_SUCCESS) {
		srs_error("hls process video message failed. ret=%d", ret);
		return ret;
	}
#endif
	
	// copy to all consumer
	if (true) {
		std::vector<SrsConsumer*>::iterator it;
		for (it = consumers.begin(); it != consumers.end(); ++it) {
			SrsConsumer* consumer = *it;
			if ((ret = consumer->enqueue(msg->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
				srs_error("dispatch the video failed. ret=%d", ret);
				return ret;
			}
		}
		srs_info("dispatch video success.");
	}

	// copy to all forwarders.
	if (true) {
		std::vector<SrsForwarder*>::iterator it;
		for (it = forwarders.begin(); it != forwarders.end(); ++it) {
			SrsForwarder* forwarder = *it;
			if ((ret = forwarder->on_video(msg->copy())) != ERROR_SUCCESS) {
				srs_error("forwarder process video message failed. ret=%d", ret);
				return ret;
			}
		}
	}

	// cache the sequence header if h264
	if (SrsCodec::video_is_sequence_header(msg->payload, msg->size)) {
		srs_freep(cache_sh_video);
		cache_sh_video = msg->copy();
		srs_trace("update video sequence header success. size=%d", msg->header.payload_length);
		return ret;
	}

	// cache the last gop packets
	if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) {
		srs_error("shrink gop cache failed. ret=%d", ret);
		return ret;
	}
	srs_verbose("cache gop success.");
	
	return ret;
}
int SrsFFMPEG::start()
{
	int ret = ERROR_SUCCESS;
	
	if (started) {
		return ret;
	}
	
	// prepare exec params
	char tmp[256];
	std::vector<std::string> params;
	
	// argv[0], set to ffmpeg bin.
	// The  execv()  and  execvp() functions ....
	// The first argument, by convention, should point to 
	// the filename associated  with  the file being executed.
	params.push_back(ffmpeg);
	
	// input.
	params.push_back("-f");
	params.push_back("flv");
	
	params.push_back("-i");
	params.push_back(input);
	
	// build the filter
	if (!vfilter.empty()) {
		std::vector<std::string>::iterator it;
		for (it = vfilter.begin(); it != vfilter.end(); ++it) {
			std::string p = *it;
			if (!p.empty()) {
				params.push_back(p);
			}
		}
	}
	
	// video specified.
	params.push_back("-vcodec");
	params.push_back(vcodec);
	
	params.push_back("-b:v");
	snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000);
	params.push_back(tmp);
	
	params.push_back("-r");
	snprintf(tmp, sizeof(tmp), "%.2f", vfps);
	params.push_back(tmp);
	
	params.push_back("-s");
	snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight);
	params.push_back(tmp);
	
	// TODO: add aspect if needed.
	params.push_back("-aspect");
	snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight);
	params.push_back(tmp);
	
	params.push_back("-threads");
	snprintf(tmp, sizeof(tmp), "%d", vthreads);
	params.push_back(tmp);
	
	params.push_back("-profile:v");
	params.push_back(vprofile);
	
	params.push_back("-preset");
	params.push_back(vpreset);
	
	// vparams
	if (!vparams.empty()) {
		std::vector<std::string>::iterator it;
		for (it = vparams.begin(); it != vparams.end(); ++it) {
			std::string p = *it;
			if (!p.empty()) {
				params.push_back(p);
			}
		}
	}
	
	// audio specified.
	params.push_back("-acodec");
	params.push_back(acodec);
	
	params.push_back("-b:a");
	snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000);
	params.push_back(tmp);
	
	params.push_back("-ar");
	snprintf(tmp, sizeof(tmp), "%d", asample_rate);
	params.push_back(tmp);
	
	params.push_back("-ac");
	snprintf(tmp, sizeof(tmp), "%d", achannels);
	params.push_back(tmp);
	
	// aparams
	if (!aparams.empty()) {
		std::vector<std::string>::iterator it;
		for (it = aparams.begin(); it != aparams.end(); ++it) {
			std::string p = *it;
			if (!p.empty()) {
				params.push_back(p);
			}
		}
	}

	// output
	params.push_back("-f");
	params.push_back("flv");
	
	params.push_back("-y");
	params.push_back(output);
	
	// TODO: fork or vfork?
	if ((pid = fork()) < 0) {
		ret = ERROR_ENCODER_FORK;
		srs_error("vfork process failed. ret=%d", ret);
		return ret;
	}
	
	// child process: ffmpeg encoder engine.
	if (pid == 0) {
		// memory leak in child process, it's ok.
		char** charpv_params = new char*[params.size() + 1];
		for (int i = 0; i < (int)params.size(); i++) {
			std::string p = params[i];
			charpv_params[i] = (char*)p.c_str();
		}
		// EOF: NULL
		charpv_params[params.size()] = NULL;
		
		// TODO: execv or execvp
		ret = execv(ffmpeg.c_str(), charpv_params);
		if (ret < 0) {
			fprintf(stderr, "fork ffmpeg failed, errno=%d(%s)", 
				errno, strerror(errno));
		}
		exit(ret);
	}

	// parent.
	if (pid > 0) {
		started = true;
		srs_trace("vfored ffmpeg encoder engine, pid=%d", pid);
		return ret;
	}
	
	return ret;
}
void handler(int signo)
{
    srs_trace("get a signal, signo=%d", signo);
    _srs_server->on_signal(signo);
}
Exemplo n.º 20
0
int main(int argc, char** argv)
{
    srs_trace("tcp server to send random data to clients.");
    if (argc <= 3) {
        srs_trace("Usage: %s <nb_writev> <port> <packet_bytes>", argv[0]);
        srs_trace("   nb_writev: the number of iovec for writev.");
        srs_trace("   port: the listen port.");
        srs_trace("   packet_bytes: the bytes for packet to send.");
        srs_trace("For example:");
        srs_trace("   %s %d %d", argv[0], 64, 1990, 4096);
        return -1;
    }
    
    int nb_writev = ::atoi(argv[1]);
    int listen_port = ::atoi(argv[2]);
    int packet_bytes = ::atoi(argv[3]);
    srs_trace("nb_writev is %d", nb_writev);
    srs_trace("listen_port is %d", listen_port);
    srs_trace("packet_bytes is %d", packet_bytes);
    
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        srs_trace("create socket failed.");
        return -1;
    }
    
    int reuse_socket = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
        srs_trace("setsockopt reuse-addr error.");
        return -1;
    }
    srs_trace("setsockopt reuse-addr success. fd=%d", fd);
    
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(listen_port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (::bind(fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
        srs_trace("bind socket error.");
        return -1;
    }
    srs_trace("bind socket success. fd=%d", fd);
    
    if (::listen(fd, 10) == -1) {
        srs_trace("listen socket error.");
        return -1;
    }
    srs_trace("listen socket success. fd=%d", fd);
    
    // get the sockoptions
    int sock_send_buffer = 0;
    socklen_t nb_sock_send_buffer = sizeof(int);
    if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sock_send_buffer, &nb_sock_send_buffer) < 0) {
        srs_trace("get sockopt failed.");
        return -1;
    }
    srs_trace("SO_SNDBUF=%d", sock_send_buffer);
    
    iovec* iov = new iovec[nb_writev];
    for (int i = 0; i < nb_writev; i++) {
        iovec& item = iov[i];
        item.iov_base = new char[packet_bytes];
        item.iov_len = packet_bytes;
    }
    
    for (;;) {
        int conn = accept(fd, NULL, NULL);
        if (conn < 0) {
            srs_trace("accept socket error.");
            return -1;
        }
        srs_trace("accept socket ok, conn=%d", conn);
        
        for (;;) {
            ssize_t nb_send = writev(conn, iov, nb_writev);
            if (nb_send != packet_bytes * nb_writev) {
                srs_trace("send bytes to socket error.");
                ::close(conn);
                break;
            }
        }
    }
    
    return 0;
}
Exemplo n.º 21
0
int SrsEdgeForwarder::connect_server()
{
    int ret = ERROR_SUCCESS;
    
    // reopen
    close_underlayer_socket();
    
    SrsConfDirective* conf = _srs_config->get_vhost_edge_origin(_req->vhost);
    srs_assert(conf);
    
    // select the origin.
    std::string server = conf->args.at(origin_index % conf->args.size());
    origin_index = (origin_index + 1) % conf->args.size();
    
    std::string s_port = RTMP_DEFAULT_PORT;
    int port = ::atoi(RTMP_DEFAULT_PORT);
    size_t pos = server.find(":");
    if (pos != std::string::npos) {
        s_port = server.substr(pos + 1);
        server = server.substr(0, pos);
        port = ::atoi(s_port.c_str());
    }
    
    // open socket.
    srs_trace("connect edge stream=%s, tcUrl=%s to server=%s, port=%d",
        _req->stream.c_str(), _req->tcUrl.c_str(), server.c_str(), port);

    // TODO: FIXME: extract utility method
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock == -1){
        ret = ERROR_SOCKET_CREATE;
        srs_error("create socket error. ret=%d", ret);
        return ret;
    }
    
    srs_assert(!stfd);
    stfd = st_netfd_open_socket(sock);
    if(stfd == NULL){
        ret = ERROR_ST_OPEN_SOCKET;
        srs_error("st_netfd_open_socket failed. ret=%d", ret);
        return ret;
    }
    
    srs_freep(client);
    srs_freep(io);
    
    io = new SrsSocket(stfd);
    client = new SrsRtmpClient(io);
    kbps->set_io(io, io);
    
    // connect to server.
    std::string ip = srs_dns_resolve(server);
    if (ip.empty()) {
        ret = ERROR_SYSTEM_IP_INVALID;
        srs_error("dns resolve server error, ip empty. ret=%d", ret);
        return ret;
    }
    
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    
    if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(sockaddr_in), SRS_EDGE_FORWARDER_TIMEOUT_US) == -1){
        ret = ERROR_ST_CONNECT;
        srs_error("connect to server error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret);
        return ret;
    }
    srs_trace("connect to server success. server=%s, ip=%s, port=%d", server.c_str(), ip.c_str(), port);
    
    return ret;
}
Exemplo n.º 22
0
int SrsEdgeForwarder::cycle()
{
    int ret = ERROR_SUCCESS;
    
    client->set_recv_timeout(SRS_PULSE_TIMEOUT_US);
    
    SrsPithyPrint pithy_print(SRS_STAGE_EDGE);

    while (pthread->can_loop()) {
        // switch to other st-threads.
        st_usleep(0);
        
        if (send_error_code != ERROR_SUCCESS) {
            st_usleep(SRS_EDGE_FORWARDER_ERROR_US);
            continue;
        }

        // read from client.
        if (true) {
            SrsMessage* msg = NULL;
            ret = client->recv_message(&msg);
            
            srs_verbose("edge loop recv message. ret=%d", ret);
            if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
                srs_error("edge forwarder recv server control message failed. ret=%d", ret);
                send_error_code = ret;
                continue;
            }
            
            srs_freep(msg);
        }
        
        // forward all messages.
        int count = 0;
        SrsSharedPtrMessage** msgs = NULL;
        if ((ret = queue->get_packets(0, msgs, count)) != ERROR_SUCCESS) {
            srs_error("get message to forward to origin failed. ret=%d", ret);
            return ret;
        }
        
        pithy_print.elapse();
        
        // pithy print
        if (pithy_print.can_print()) {
            kbps->sample();
            srs_trace("-> "SRS_LOG_ID_EDGE_PUBLISH
                " time=%"PRId64", msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d", 
                pithy_print.age(), count,
                kbps->get_send_kbps(), kbps->get_send_kbps_sample_high(), kbps->get_send_kbps_sample_medium(),
                kbps->get_recv_kbps(), kbps->get_recv_kbps_sample_high(), kbps->get_recv_kbps_sample_medium());
        }
        
        // ignore when no messages.
        if (count <= 0) {
            srs_verbose("no packets to forward.");
            continue;
        }
        SrsAutoFreeArray(SrsSharedPtrMessage, msgs, count);
    
        // all msgs to forward to origin.
        // @remark, becareful, all msgs must be free explicitly,
        //      free by send_and_free_message or srs_freep.
        for (int i = 0; i < count; i++) {
            SrsSharedPtrMessage* msg = msgs[i];
            
            srs_assert(msg);
            msgs[i] = NULL;
            
            if ((ret = client->send_and_free_message(msg, stream_id)) != ERROR_SUCCESS) {
                srs_error("edge publish forwarder send message to server failed. ret=%d", ret);
                return ret;
            }
        }
    }
    
    return ret;
}
int SrsForwarder::forward()
{
    int ret = ERROR_SUCCESS;
    
    client->set_recv_timeout(SRS_PULSE_TIMEOUT_US);
    
    SrsPithyPrint pithy_print(SRS_STAGE_FORWARDER);

    while (pthread->can_loop()) {
        // switch to other st-threads.
        st_usleep(0);

        // read from client.
        if (true) {
            SrsCommonMessage* msg = NULL;
            ret = client->recv_message(&msg);
            
            srs_verbose("play loop recv message. ret=%d", ret);
            if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
                srs_error("recv server control message failed. ret=%d", ret);
                return ret;
            }
        }
        
        // forward all messages.
        int count = 0;
        SrsSharedPtrMessage** msgs = NULL;
        if ((ret = queue->get_packets(0, msgs, count)) != ERROR_SUCCESS) {
            srs_error("get message to forward failed. ret=%d", ret);
            return ret;
        }
        
        // ignore when no messages.
        if (count <= 0) {
            srs_verbose("no packets to forward.");
            continue;
        }
        SrsAutoFree(SrsSharedPtrMessage*, msgs, true);

        // pithy print
        pithy_print.elapse(SRS_PULSE_TIMEOUT_US / 1000);
        if (pithy_print.can_print()) {
            srs_trace("-> time=%"PRId64", msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d", 
                pithy_print.get_age(), count, client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());
        }
    
        // all msgs to forward.
        for (int i = 0; i < count; i++) {
            SrsSharedPtrMessage* msg = msgs[i];
            
            srs_assert(msg);
            msgs[i] = NULL;
            
            if ((ret = client->send_message(msg)) != ERROR_SUCCESS) {
                srs_error("forwarder send message to server failed. ret=%d", ret);
                return ret;
            }
        }
    }
    
    return ret;
}