/** * The MIT License (MIT) * * Copyright (c) 2013-2018 Winlin * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "../../objs/include/srs_librtmp.h" int main(int argc, char** argv) { int ret = 0; srs_rtmp_t rtmp; // time int64_t time_startup = srs_utils_time_ms(); int64_t time_dns_resolve = 0; int64_t time_socket_connect = 0; int64_t time_play_stream = 0; int64_t time_first_packet = 0; int64_t time_cleanup = 0; // bytes int64_t bytes_nsend = 0; int time_duration = 0; int64_t bytes_nrecv = 0; // packet data int size; char type; char* data; uint32_t timestamp; uint32_t basetime = 0; // user options const char* rtmp_url = NULL; int duration = 0; int timeout = 0; enum srs_url_schema sus; printf("detect rtmp stream\n"); printf("srs(ossrs) client librtmp library.\n"); printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); if (argc <= 3) { printf("detect stream on RTMP server, print result to stderr.\n" "Usage: %s [url_schema]\n" " rtmp_url RTMP stream url to play\n" " duration how long to play, in seconds, stream time.\n" " timeout how long to timeout, in seconds, system time.\n" " url_schema the schema of url, default to vis, can be:\n" " normal: rtmp://vhost:port/app/stream\n" " via : rtmp://ip:port/vhost/app/stream\n" " vis : rtmp://ip:port/app/stream?vhost=xxx\n" " vis2 : rtmp://ip:port/app/stream?domain=xxx\n" "For example:\n" " %s rtmp://127.0.0.1:1935/bravo.chnvideo.com/live/livestream 3 10\n", argv[0], argv[0]); exit(-1); } rtmp_url = argv[1]; duration = atoi(argv[2]); timeout = atoi(argv[3]); if (1) { char *p = "vis"; if (argc > 4) { p = argv[4]; } if (strcmp(p, "normal") == 0) { sus = srs_url_schema_normal; } else if (strcmp(p, "via") == 0) { sus = srs_url_schema_via; } else if (strcmp(p, "vis") == 0) { sus = srs_url_schema_vis; } else if (strcmp(p, "vis2") == 0){ sus = srs_url_schema_vis2; } else { srs_human_trace("url_schema must be normal/via/vis/vis2"); exit(-2); } srs_human_trace("url schema: %s", p); } srs_human_trace("rtmp url: %s", rtmp_url); srs_human_trace("duration: %ds, timeout:%ds", duration, timeout); if (duration <= 0 || timeout <= 0) { srs_human_trace("duration and timeout must be positive."); exit(-3); } if ((rtmp = srs_rtmp_create(rtmp_url)) == NULL) { srs_human_trace("create rtmp failed"); ret = -1; goto rtmp_destroy; } if ((ret = srs_rtmp_set_timeout(rtmp, timeout * 1000, timeout * 1000)) != 0) { srs_human_trace("set timeout for rtmp failed. errno=%d", ret); goto rtmp_destroy; } if ((ret = srs_rtmp_dns_resolve(rtmp)) != 0) { srs_human_trace("dns resolve failed. ret=%d", ret); goto rtmp_destroy; } srs_human_trace("dns resolve success"); time_dns_resolve = srs_utils_time_ms(); if ((ret = srs_rtmp_connect_server(rtmp)) != 0) { srs_human_trace("socket connect failed. ret=%d", ret); goto rtmp_destroy; } srs_human_trace("socket connect success"); time_socket_connect = srs_utils_time_ms(); if ((ret = srs_rtmp_do_simple_handshake(rtmp)) != 0) { srs_human_trace("do simple handshake failed. ret=%d", ret); goto rtmp_destroy; } srs_human_trace("do simple handshake success"); if ((ret = srs_rtmp_set_schema(rtmp, sus)) != 0) { srs_human_trace("set url schema=%d failed, ret=%d", sus, ret); goto rtmp_destroy; } if ((ret = srs_rtmp_connect_app(rtmp)) != 0) { srs_human_trace("connect vhost/app failed. ret=%d", ret); goto rtmp_destroy; } srs_human_trace("connect vhost/app success"); if ((ret = srs_rtmp_play_stream(rtmp)) != 0) { srs_human_trace("play stream failed. ret=%d", ret); goto rtmp_destroy; } srs_human_trace("play stream success"); time_play_stream = srs_utils_time_ms(); for (;;) { if ((ret = srs_rtmp_read_packet(rtmp, &type, ×tamp, &data, &size)) != 0) { srs_human_trace("read packet failed. ret=%d", ret); goto rtmp_destroy; } srs_human_trace("got packet: type=%s, time=%d, size=%d", srs_human_flv_tag_type2string(type), timestamp, size); if (SRS_RTMP_TYPE_VIDEO == type || SRS_RTMP_TYPE_AUDIO == type) { if (time_first_packet <= 0) { time_first_packet = srs_utils_time_ms(); } if (basetime <= 0) { basetime = timestamp; } } free(data); if (srs_utils_time_ms() - time_startup > timeout * 1000) { srs_human_trace("timeout, terminate."); goto rtmp_destroy; } if (timestamp > basetime && (timestamp - basetime) > duration * 1000) { srs_human_trace("duration exceed, terminate."); goto rtmp_destroy; } } rtmp_destroy: bytes_nsend = srs_utils_send_bytes(rtmp); bytes_nrecv = srs_utils_recv_bytes(rtmp); srs_rtmp_destroy(rtmp); time_cleanup = srs_utils_time_ms(); time_duration = (int)(time_cleanup - time_startup); // print result to stderr. fprintf(stderr, "{" "\"%s\":%d, " //#0 "\"%s\":%d, " //#1 "\"%s\":%d, " // #2 "\"%s\":%d, " // #3 "\"%s\":%d, " // #4 "\"%s\":%d, " // #5 "\"%s\":%d, " // #6 "\"%s\":%d, " // #7 "\"%s\":%d, " // #8 "\"%s\":%d, " // #9 "\"%s\":%d, " // #10 "%s,%s,%s,%s}", "code", ret, //#0 // total = dns + tcp_connect + start_play + first_packet + last_packet "total", time_duration, //#1 "dns", (int)(time_dns_resolve - time_startup), //#2 "tcp_connect", (int)(time_socket_connect - time_dns_resolve), //#3 "start_play", (int)(time_play_stream - time_socket_connect), //#4 "first_packet", (int)(time_first_packet - time_play_stream), //#5 "last_packet", (int)(time_cleanup - time_first_packet), //#6 "stream", (int)(timestamp - basetime), //#7 // expect = time_cleanup - time_first_packet // actual = stream // delay = actual - expect "delay", (int)(timestamp - basetime - (time_cleanup - time_first_packet)), //#8 "publish_kbps", (int)((time_duration <= 0)? 0:(bytes_nsend * 8 / time_duration)), //#9 "play_kbps", (int)((time_duration <= 0)? 0:(bytes_nrecv * 8 / time_duration)), //#10 // unit in ms. "\"unit\": \"ms\"", "\"remark0\": \"total = dns + tcp_connect + start_play + first_packet + last_packet\"", "\"remark1\": \"delay = stream - (time_cleanup - time_first_packet)\"", "\"remark2\": \"if code is not 0, user must ignore all data\"" ); srs_human_trace(" "); srs_human_trace("completed"); return ret; }