winlin

for bug #215, srs rtmp dump support conn args. 2.0.90

@@ -26,34 +26,194 @@ gcc srs_rtmp_dump.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_rtmp_dum @@ -26,34 +26,194 @@ gcc srs_rtmp_dump.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_rtmp_dum
26 26
27 #include <stdio.h> 27 #include <stdio.h>
28 #include <stdlib.h> 28 #include <stdlib.h>
  29 +#include <unistd.h>
  30 +#include <getopt.h>
  31 +#include <assert.h>
29 32
30 #include "../../objs/include/srs_librtmp.h" 33 #include "../../objs/include/srs_librtmp.h"
31 34
  35 +void parse_amf0_object(char* p, srs_amf0_t args)
  36 +{
  37 + char opvt = 0; // object property value type.
  38 + const char* opnp = NULL; // object property name ptr.
  39 + const char* opvp = NULL; // object property value ptr.
  40 +
  41 + while (*p) {
  42 + switch (*p++) {
  43 + case 'O':
  44 + while (*p && *p++ != ':') {
  45 + }
  46 + if (*p++ == '1') {
  47 + printf("amf0 object start\n");
  48 + } else {
  49 + printf("amf0 object end\n");
  50 + }
  51 + break;
  52 + case 'N':
  53 + opvt = *p++;
  54 + if (*p++ != ':') {
  55 + printf("object property must split by :.\n");
  56 + exit(-1);
  57 + }
  58 + opnp = p++;
  59 + while (*p && *p++ != ':') {
  60 + }
  61 + p[-1] = 0;
  62 + opvp = p;
  63 + printf("amf0 %c property[%s]=%s\n", opvt, opnp, opvp);
  64 + switch(opvt) {
  65 + case 'S':
  66 + srs_amf0_object_property_set(args, opnp, srs_amf0_create_string(opvp));
  67 + break;
  68 + default:
  69 + printf("unsupported object property.\n");
  70 + exit(-1);
  71 + }
  72 + *p=0;
  73 + break;
  74 + default:
  75 + printf("only supports an object arg.\n");
  76 + exit(-1);
  77 + }
  78 + }
  79 +}
  80 +
32 int main(int argc, char** argv) 81 int main(int argc, char** argv)
33 { 82 {
34 printf("dump rtmp stream to flv file\n"); 83 printf("dump rtmp stream to flv file\n");
35 printf("srs(simple-rtmp-server) client librtmp library.\n"); 84 printf("srs(simple-rtmp-server) client librtmp library.\n");
36 printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); 85 printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision());
  86 + printf("@refer to http://rtmpdump.mplayerhq.hu/rtmpdump.1.html\n");
  87 +
  88 + struct option long_options[] = {
  89 + {"rtmp", required_argument, 0, 'r'},
  90 + {"flv", required_argument, 0, 'o'},
  91 + {"swfUrl", required_argument, 0, 's'},
  92 + {"tcUrl", required_argument, 0, 't'},
  93 + {"pageUrl", required_argument, 0, 'p'},
  94 + {"conn", required_argument, 0, 'C'},
  95 + {"complex", no_argument, 0, 'x'},
  96 + {"help", no_argument, 0, 'h'},
  97 + {0, 0, 0, 0}
  98 + };
  99 +
  100 + int show_help = 0;
  101 + int complex_handshake = 0;
  102 + const char* rtmp_url = NULL;
  103 + const char* output_flv = NULL;
  104 + const char* swfUrl = NULL;
  105 + const char* tcUrl = NULL;
  106 + const char* pageUrl = NULL;
  107 + srs_amf0_t args = NULL;
37 108
38 - if (argc <= 2) {  
39 - printf("Usage: %s <rtmp_url> <flv_path>\n"  
40 - " rtmp_url RTMP stream url to play\n"  
41 - " flv_path The flv file path to save\n" 109 + int opt = 0;
  110 + int option_index = 0;
  111 + while((opt = getopt_long(argc, argv, "hxr:o:s:t:p:C:", long_options, &option_index)) != -1){
  112 + switch(opt){
  113 + case 'r':
  114 + rtmp_url = optarg;
  115 + break;
  116 + case 'o':
  117 + output_flv = optarg;
  118 + break;
  119 + case 's':
  120 + swfUrl = optarg;
  121 + break;
  122 + case 't':
  123 + tcUrl = optarg;
  124 + break;
  125 + case 'p':
  126 + pageUrl = optarg;
  127 + break;
  128 + case 'C':
  129 + if (!args) {
  130 + args = srs_amf0_create_object();
  131 + }
  132 + char* p = (char*)optarg;
  133 + parse_amf0_object(p, args);
  134 + break;
  135 + case 'x':
  136 + complex_handshake = 1;
  137 + break;
  138 + case 'h':
  139 + show_help = 1;
  140 + break;
  141 + default:
  142 + printf("unsupported opt.\n");
  143 + exit(-1);
  144 + }
  145 + }
  146 +
  147 + if (!rtmp_url || show_help) {
  148 + printf("Usage: %s -r url [-o output] [-s swfUrl] [-t tcUrl] [-p pageUrl] [-C conndata] [--complex] [-h]\n"
  149 + "Options:\n"
  150 + " --rtmp -r url\n"
  151 + " URL of the server and media content.\n"
  152 + " --flv -o output\n"
  153 + " Specify the output file name. If the name is − or is omitted, the stream is written to stdout.\n"
  154 + " --complex\n"
  155 + " Whether use complex handshake(srs-librtmp with ssl required).\n"
  156 + " --swfUrl -s url\n"
  157 + " URL of the SWF player for the media. By default no value will be sent.\n"
  158 + " --tcUrl -t url\n"
  159 + " URL of the target stream. Defaults to rtmp[e]://host[:port]/app/playpath.\n"
  160 + " --pageUrl -p url\n"
  161 + " URL of the web page in which the media was embedded. By default no value will be sent.\n"
  162 + " −−conn −C type:data\n"
  163 + " Append arbitrary AMF data to the Connect message. The type must be B for Boolean, N for number, S for string, O for object, or Z for null. For Booleans the data must be either 0 or 1 for FALSE or TRUE, respectively. Likewise for Objects the data must be 0 or 1 to end or begin an object, respectively. Data items in subobjects may be named, by prefixing the type with 'N' and specifying the name before the value, e.g. NB:myFlag:1. This option may be used multiple times to construct arbitrary AMF sequences. E.g.\n"
  164 + " −C B:1 −C S:authMe −C O:1 −C NN:code:1.23 −C NS:flag:ok −C O:0\n"
  165 + " -C O:1 -C NS:CONN:\" -C B:4Rg9vr0\" -C O:0\n"
  166 + " @remark, support a object args only.\n"
  167 + " --help -h\n"
  168 + " Print a summary of command options.\n"
42 "For example:\n" 169 "For example:\n"
43 - " %s rtmp://127.0.0.1:1935/live/livestream output.flv\n",  
44 - argv[0], argv[0]); 170 + " %s -r rtmp://127.0.0.1:1935/live/livestream -o output.flv\n"
  171 + " %s -h\n",
  172 + argv[0], argv[0], argv[0]);
45 exit(-1); 173 exit(-1);
46 } 174 }
47 175
48 - srs_human_trace("rtmp url: %s", argv[1]);  
49 - srs_human_trace("flv path: %s", argv[2]);  
50 - srs_rtmp_t rtmp = srs_rtmp_create(argv[1]); 176 + srs_human_trace("rtmp url: %s", rtmp_url);
  177 + srs_human_trace("handshake: %s", (complex_handshake? "complex" : "simple"));
  178 + srs_human_trace("swfUrl: %s", swfUrl);
  179 + srs_human_trace("pageUrl: %s", pageUrl);
  180 + srs_human_trace("tcUrl: %s", tcUrl);
  181 + if (output_flv) {
  182 + srs_human_trace("flv output path: %s", output_flv);
  183 + } else {
  184 + srs_human_trace("output to console");
  185 + }
  186 +
  187 + srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url);
  188 +
  189 + if (__srs_rtmp_dns_resolve(rtmp) != 0) {
  190 + srs_human_trace("dns resolve failed.");
  191 + goto rtmp_destroy;
  192 + }
  193 +
  194 + if (__srs_rtmp_connect_server(rtmp) != 0) {
  195 + srs_human_trace("connect to server failed.");
  196 + goto rtmp_destroy;
  197 + }
  198 +
  199 + if (complex_handshake) {
  200 + if (__srs_rtmp_do_complex_handshake(rtmp) != 0) {
  201 + srs_human_trace("complex handshake failed.");
  202 + goto rtmp_destroy;
  203 + }
  204 + srs_human_trace("do complex handshake success");
  205 + } else {
  206 + if (__srs_rtmp_do_simple_handshake(rtmp) != 0) {
  207 + srs_human_trace("simple handshake failed.");
  208 + goto rtmp_destroy;
  209 + }
  210 + srs_human_trace("do simple handshake success");
  211 + }
51 212
52 - if (srs_rtmp_handshake(rtmp) != 0) {  
53 - srs_human_trace("simple handshake failed."); 213 + if (srs_rtmp_set_connect_args(rtmp, tcUrl, swfUrl, pageUrl, args) != 0) {
  214 + srs_human_trace("set connect args failed.");
54 goto rtmp_destroy; 215 goto rtmp_destroy;
55 } 216 }
56 - srs_human_trace("simple handshake success");  
57 217
58 if (srs_rtmp_connect_app(rtmp) != 0) { 218 if (srs_rtmp_connect_app(rtmp) != 0) {
59 srs_human_trace("connect vhost/app failed."); 219 srs_human_trace("connect vhost/app failed.");
@@ -67,26 +227,31 @@ int main(int argc, char** argv) @@ -67,26 +227,31 @@ int main(int argc, char** argv)
67 } 227 }
68 srs_human_trace("play stream success"); 228 srs_human_trace("play stream success");
69 229
70 - srs_flv_t flv = srs_flv_open_write(argv[2]);  
71 -  
72 - // flv header  
73 - char header[9];  
74 - // 3bytes, signature, "FLV",  
75 - header[0] = 'F';  
76 - header[1] = 'L';  
77 - header[2] = 'V';  
78 - // 1bytes, version, 0x01,  
79 - header[3] = 0x01;  
80 - // 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present.  
81 - header[4] = 0x03; // audio + video.  
82 - // 4bytes, dataoffset  
83 - header[5] = 0x00;  
84 - header[6] = 0x00;  
85 - header[7] = 0x00;  
86 - header[8] = 0x09;  
87 - if (srs_flv_write_header(flv, header) != 0) {  
88 - srs_human_trace("write flv header failed.");  
89 - goto rtmp_destroy; 230 + srs_flv_t flv = NULL;
  231 + if (output_flv) {
  232 + flv = srs_flv_open_write(output_flv);
  233 + }
  234 +
  235 + if (flv) {
  236 + // flv header
  237 + char header[9];
  238 + // 3bytes, signature, "FLV",
  239 + header[0] = 'F';
  240 + header[1] = 'L';
  241 + header[2] = 'V';
  242 + // 1bytes, version, 0x01,
  243 + header[3] = 0x01;
  244 + // 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present.
  245 + header[4] = 0x03; // audio + video.
  246 + // 4bytes, dataoffset
  247 + header[5] = 0x00;
  248 + header[6] = 0x00;
  249 + header[7] = 0x00;
  250 + header[8] = 0x09;
  251 + if (srs_flv_write_header(flv, header) != 0) {
  252 + srs_human_trace("write flv header failed.");
  253 + goto rtmp_destroy;
  254 + }
90 } 255 }
91 256
92 for (;;) { 257 for (;;) {
@@ -105,9 +270,11 @@ int main(int argc, char** argv) @@ -105,9 +270,11 @@ int main(int argc, char** argv)
105 goto rtmp_destroy; 270 goto rtmp_destroy;
106 } 271 }
107 272
108 - if (srs_flv_write_tag(flv, type, timestamp, data, size) != 0) {  
109 - srs_human_trace("dump rtmp packet failed.");  
110 - goto rtmp_destroy; 273 + if (flv) {
  274 + if (srs_flv_write_tag(flv, type, timestamp, data, size) != 0) {
  275 + srs_human_trace("dump rtmp packet failed.");
  276 + goto rtmp_destroy;
  277 + }
111 } 278 }
112 279
113 free(data); 280 free(data);
@@ -115,7 +282,9 @@ int main(int argc, char** argv) @@ -115,7 +282,9 @@ int main(int argc, char** argv)
115 282
116 rtmp_destroy: 283 rtmp_destroy:
117 srs_rtmp_destroy(rtmp); 284 srs_rtmp_destroy(rtmp);
118 - srs_flv_close(flv); 285 + if (flv) {
  286 + srs_flv_close(flv);
  287 + }
119 srs_human_trace("completed"); 288 srs_human_trace("completed");
120 289
121 return 0; 290 return 0;
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 89 34 +#define VERSION_REVISION 90
35 // server info. 35 // server info.
36 #define RTMP_SIG_SRS_KEY "SRS" 36 #define RTMP_SIG_SRS_KEY "SRS"
37 #define RTMP_SIG_SRS_ROLE "origin/edge server" 37 #define RTMP_SIG_SRS_ROLE "origin/edge server"
@@ -66,6 +66,9 @@ struct Context @@ -66,6 +66,9 @@ struct Context
66 std::string app; 66 std::string app;
67 std::string stream; 67 std::string stream;
68 std::string param; 68 std::string param;
  69 +
  70 + // extra request object for connect to server, NULL to ignore.
  71 + SrsRequest* req;
69 72
70 SrsRtmpClient* rtmp; 73 SrsRtmpClient* rtmp;
71 SimpleSocketStream* skt; 74 SimpleSocketStream* skt;
@@ -93,12 +96,14 @@ struct Context @@ -93,12 +96,14 @@ struct Context
93 Context() { 96 Context() {
94 rtmp = NULL; 97 rtmp = NULL;
95 skt = NULL; 98 skt = NULL;
  99 + req = NULL;
96 stream_id = 0; 100 stream_id = 0;
97 h264_sps_pps_sent = false; 101 h264_sps_pps_sent = false;
98 h264_sps_changed = false; 102 h264_sps_changed = false;
99 h264_pps_changed = false; 103 h264_pps_changed = false;
100 } 104 }
101 virtual ~Context() { 105 virtual ~Context() {
  106 + srs_freep(req);
102 srs_freep(rtmp); 107 srs_freep(rtmp);
103 srs_freep(skt); 108 srs_freep(skt);
104 } 109 }
@@ -595,6 +600,53 @@ int __srs_rtmp_connect_server(srs_rtmp_t rtmp) @@ -595,6 +600,53 @@ int __srs_rtmp_connect_server(srs_rtmp_t rtmp)
595 return ret; 600 return ret;
596 } 601 }
597 602
  603 +int __srs_rtmp_do_complex_handshake(srs_rtmp_t rtmp)
  604 +{
  605 + int ret = ERROR_SUCCESS;
  606 +
  607 + srs_assert(rtmp != NULL);
  608 + Context* context = (Context*)rtmp;
  609 +
  610 + srs_assert(context->skt != NULL);
  611 +
  612 + // simple handshake
  613 + srs_freep(context->rtmp);
  614 + context->rtmp = new SrsRtmpClient(context->skt);
  615 +
  616 + if ((ret = context->rtmp->complex_handshake()) != ERROR_SUCCESS) {
  617 + return ret;
  618 + }
  619 +
  620 + return ret;
  621 +}
  622 +
  623 +int srs_rtmp_set_connect_args(srs_rtmp_t rtmp,
  624 + const char* tcUrl, const char* swfUrl, const char* pageUrl, srs_amf0_t args
  625 +) {
  626 + int ret = ERROR_SUCCESS;
  627 +
  628 + srs_assert(rtmp != NULL);
  629 + Context* context = (Context*)rtmp;
  630 +
  631 + srs_freep(context->req);
  632 + context->req = new SrsRequest();
  633 +
  634 + if (args) {
  635 + context->req->args = (SrsAmf0Object*)args;
  636 + }
  637 + if (tcUrl) {
  638 + context->req->tcUrl = tcUrl;
  639 + }
  640 + if (swfUrl) {
  641 + context->req->swfUrl = swfUrl;
  642 + }
  643 + if (pageUrl) {
  644 + context->req->pageUrl = pageUrl;
  645 + }
  646 +
  647 + return ret;
  648 +}
  649 +
598 int __srs_rtmp_do_simple_handshake(srs_rtmp_t rtmp) 650 int __srs_rtmp_do_simple_handshake(srs_rtmp_t rtmp)
599 { 651 {
600 int ret = ERROR_SUCCESS; 652 int ret = ERROR_SUCCESS;
@@ -628,7 +680,7 @@ int srs_rtmp_connect_app(srs_rtmp_t rtmp) @@ -628,7 +680,7 @@ int srs_rtmp_connect_app(srs_rtmp_t rtmp)
628 ); 680 );
629 681
630 if ((ret = context->rtmp->connect_app( 682 if ((ret = context->rtmp->connect_app(
631 - context->app, tcUrl, NULL, true)) != ERROR_SUCCESS) 683 + context->app, tcUrl, context->req, true)) != ERROR_SUCCESS)
632 { 684 {
633 return ret; 685 return ret;
634 } 686 }
@@ -1725,6 +1777,11 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) @@ -1725,6 +1777,11 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed)
1725 return amf0; 1777 return amf0;
1726 } 1778 }
1727 1779
  1780 +srs_amf0_t srs_amf0_create_string(const char* value)
  1781 +{
  1782 + return SrsAmf0Any::str(value);
  1783 +}
  1784 +
1728 srs_amf0_t srs_amf0_create_number(srs_amf0_number value) 1785 srs_amf0_t srs_amf0_create_number(srs_amf0_number value)
1729 { 1786 {
1730 return SrsAmf0Any::number(value); 1787 return SrsAmf0Any::number(value);
@@ -2374,6 +2431,9 @@ int srs_human_print_rtmp_packet(char type, u_int32_t timestamp, char* data, int @@ -2374,6 +2431,9 @@ int srs_human_print_rtmp_packet(char type, u_int32_t timestamp, char* data, int
2374 2431
2375 u_int32_t pts; 2432 u_int32_t pts;
2376 if (srs_utils_parse_timestamp(timestamp, type, data, size, &pts) != 0) { 2433 if (srs_utils_parse_timestamp(timestamp, type, data, size, &pts) != 0) {
  2434 + srs_human_trace("Video packet type=%s, dts=%d, pts=%d, size=%d, DecodeError",
  2435 + srs_human_flv_tag_type2string(type), timestamp, pts, size
  2436 + );
2377 return ret; 2437 return ret;
2378 } 2438 }
2379 2439
@@ -86,6 +86,7 @@ extern int srs_version_revision(); @@ -86,6 +86,7 @@ extern int srs_version_revision();
86 *************************************************************/ 86 *************************************************************/
87 // the RTMP handler. 87 // the RTMP handler.
88 typedef void* srs_rtmp_t; 88 typedef void* srs_rtmp_t;
  89 +typedef void* srs_amf0_t;
89 90
90 /** 91 /**
91 * create/destroy a rtmp protocol stack. 92 * create/destroy a rtmp protocol stack.
@@ -142,6 +143,18 @@ extern int __srs_rtmp_dns_resolve(srs_rtmp_t rtmp); @@ -142,6 +143,18 @@ extern int __srs_rtmp_dns_resolve(srs_rtmp_t rtmp);
142 extern int __srs_rtmp_connect_server(srs_rtmp_t rtmp); 143 extern int __srs_rtmp_connect_server(srs_rtmp_t rtmp);
143 // do simple handshake over socket. 144 // do simple handshake over socket.
144 extern int __srs_rtmp_do_simple_handshake(srs_rtmp_t rtmp); 145 extern int __srs_rtmp_do_simple_handshake(srs_rtmp_t rtmp);
  146 +// do complex handshake over socket.
  147 +extern int __srs_rtmp_do_complex_handshake(srs_rtmp_t rtmp);
  148 +
  149 +/**
  150 +* set the args of connect packet for rtmp.
  151 +* @param args, the extra amf0 object args.
  152 +* @remark, all params can be NULL to ignore.
  153 +* @remark, user should never free the args for we directly use it.
  154 +*/
  155 +extern int srs_rtmp_set_connect_args(srs_rtmp_t rtmp,
  156 + const char* tcUrl, const char* swfUrl, const char* pageUrl, srs_amf0_t args
  157 +);
145 158
146 /** 159 /**
147 * connect to rtmp vhost/app 160 * connect to rtmp vhost/app
@@ -546,7 +559,6 @@ extern srs_bool srs_flv_is_keyframe(char* data, int32_t size); @@ -546,7 +559,6 @@ extern srs_bool srs_flv_is_keyframe(char* data, int32_t size);
546 ************************************************************** 559 **************************************************************
547 *************************************************************/ 560 *************************************************************/
548 /* the output handler. */ 561 /* the output handler. */
549 -typedef void* srs_amf0_t;  
550 typedef double srs_amf0_number; 562 typedef double srs_amf0_number;
551 /** 563 /**
552 * parse amf0 from data. 564 * parse amf0 from data.
@@ -555,6 +567,7 @@ typedef double srs_amf0_number; @@ -555,6 +567,7 @@ typedef double srs_amf0_number;
555 * @remark user must free the parsed or created object by srs_amf0_free. 567 * @remark user must free the parsed or created object by srs_amf0_free.
556 */ 568 */
557 extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); 569 extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed);
  570 +extern srs_amf0_t srs_amf0_create_string(const char* value);
558 extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value); 571 extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value);
559 extern srs_amf0_t srs_amf0_create_ecma_array(); 572 extern srs_amf0_t srs_amf0_create_ecma_array();
560 extern srs_amf0_t srs_amf0_create_strict_array(); 573 extern srs_amf0_t srs_amf0_create_strict_array();
@@ -469,13 +469,17 @@ int SrsRtmpClient::connect_app2( @@ -469,13 +469,17 @@ int SrsRtmpClient::connect_app2(
469 SrsConnectAppPacket* pkt = new SrsConnectAppPacket(); 469 SrsConnectAppPacket* pkt = new SrsConnectAppPacket();
470 470
471 pkt->command_object->set("app", SrsAmf0Any::str(app.c_str())); 471 pkt->command_object->set("app", SrsAmf0Any::str(app.c_str()));
472 - pkt->command_object->set("flashVer", SrsAmf0Any::str("WIN 12,0,0,41")); 472 + pkt->command_object->set("flashVer", SrsAmf0Any::str("WIN 15,0,0,239"));
473 if (req) { 473 if (req) {
474 pkt->command_object->set("swfUrl", SrsAmf0Any::str(req->swfUrl.c_str())); 474 pkt->command_object->set("swfUrl", SrsAmf0Any::str(req->swfUrl.c_str()));
475 } else { 475 } else {
476 pkt->command_object->set("swfUrl", SrsAmf0Any::str()); 476 pkt->command_object->set("swfUrl", SrsAmf0Any::str());
477 } 477 }
478 - pkt->command_object->set("tcUrl", SrsAmf0Any::str(tc_url.c_str())); 478 + if (req && req->tcUrl != "") {
  479 + pkt->command_object->set("tcUrl", SrsAmf0Any::str(req->tcUrl.c_str()));
  480 + } else {
  481 + pkt->command_object->set("tcUrl", SrsAmf0Any::str(tc_url.c_str()));
  482 + }
479 pkt->command_object->set("fpad", SrsAmf0Any::boolean(false)); 483 pkt->command_object->set("fpad", SrsAmf0Any::boolean(false));
480 pkt->command_object->set("capabilities", SrsAmf0Any::number(239)); 484 pkt->command_object->set("capabilities", SrsAmf0Any::number(239));
481 pkt->command_object->set("audioCodecs", SrsAmf0Any::number(3575)); 485 pkt->command_object->set("audioCodecs", SrsAmf0Any::number(3575));
@@ -31,7 +31,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include <srs_protocol_buffer.hpp> 31 #include <srs_protocol_buffer.hpp>
32 #include <srs_protocol_utility.hpp> 32 #include <srs_protocol_utility.hpp>
33 33
  34 +// for srs-librtmp, @see https://github.com/winlinvip/simple-rtmp-server/issues/213
  35 +#ifndef _WIN32
34 #include <unistd.h> 36 #include <unistd.h>
  37 +#endif
  38 +
35 #include <stdlib.h> 39 #include <stdlib.h>
36 using namespace std; 40 using namespace std;
37 41
@@ -868,9 +872,14 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -868,9 +872,14 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
868 int SrsProtocol::do_iovs_send(iovec* iovs, int size) 872 int SrsProtocol::do_iovs_send(iovec* iovs, int size)
869 { 873 {
870 int ret = ERROR_SUCCESS; 874 int ret = ERROR_SUCCESS;
871 - 875 +
872 // the limits of writev iovs. 876 // the limits of writev iovs.
  877 + // for srs-librtmp, @see https://github.com/winlinvip/simple-rtmp-server/issues/213
  878 +#ifndef _WIN32
873 static int limits = sysconf(_SC_IOV_MAX); 879 static int limits = sysconf(_SC_IOV_MAX);
  880 +#else
  881 + static int limits = 1024;
  882 +#endif
874 883
875 // send in a time. 884 // send in a time.
876 if (size < limits) { 885 if (size < limits) {