mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			239 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * 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 <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #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 <rtmp_url> <duration> <timeout> [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;
 | |
| }
 |