refine the protocol and amf0, extract the template method as global static method
正在显示
9 个修改的文件
包含
455 行增加
和
391 行删除
@@ -50,6 +50,123 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -50,6 +50,123 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
50 | // origin array whos data takes the same form as LengthValueBytes | 50 | // origin array whos data takes the same form as LengthValueBytes |
51 | #define RTMP_AMF0_OriginStrictArray 0x20 | 51 | #define RTMP_AMF0_OriginStrictArray 0x20 |
52 | 52 | ||
53 | +// User defined | ||
54 | +#define RTMP_AMF0_Invalid 0x3F | ||
55 | + | ||
56 | +SrsAmf0Any::SrsAmf0Any() | ||
57 | +{ | ||
58 | + marker = RTMP_AMF0_Invalid; | ||
59 | +} | ||
60 | + | ||
61 | +SrsAmf0Any::~SrsAmf0Any() | ||
62 | +{ | ||
63 | +} | ||
64 | + | ||
65 | +bool SrsAmf0Any::is_string() | ||
66 | +{ | ||
67 | + return marker == RTMP_AMF0_String; | ||
68 | +} | ||
69 | + | ||
70 | +bool SrsAmf0Any::is_boolean() | ||
71 | +{ | ||
72 | + return marker == RTMP_AMF0_Boolean; | ||
73 | +} | ||
74 | + | ||
75 | +bool SrsAmf0Any::is_number() | ||
76 | +{ | ||
77 | + return marker == RTMP_AMF0_Number; | ||
78 | +} | ||
79 | + | ||
80 | +bool SrsAmf0Any::is_object() | ||
81 | +{ | ||
82 | + return marker == RTMP_AMF0_Object; | ||
83 | +} | ||
84 | + | ||
85 | +bool SrsAmf0Any::is_object_eof() | ||
86 | +{ | ||
87 | + return marker == RTMP_AMF0_ObjectEnd; | ||
88 | +} | ||
89 | + | ||
90 | +SrsAmf0String::SrsAmf0String() | ||
91 | +{ | ||
92 | + marker = RTMP_AMF0_String; | ||
93 | +} | ||
94 | + | ||
95 | +SrsAmf0String::~SrsAmf0String() | ||
96 | +{ | ||
97 | +} | ||
98 | + | ||
99 | +SrsAmf0Boolean::SrsAmf0Boolean() | ||
100 | +{ | ||
101 | + marker = RTMP_AMF0_Boolean; | ||
102 | + value = false; | ||
103 | +} | ||
104 | + | ||
105 | +SrsAmf0Boolean::~SrsAmf0Boolean() | ||
106 | +{ | ||
107 | +} | ||
108 | + | ||
109 | +SrsAmf0Number::SrsAmf0Number() | ||
110 | +{ | ||
111 | + marker = RTMP_AMF0_Number; | ||
112 | + value = 0; | ||
113 | +} | ||
114 | + | ||
115 | +SrsAmf0Number::~SrsAmf0Number() | ||
116 | +{ | ||
117 | + marker = RTMP_AMF0_ObjectEnd; | ||
118 | +} | ||
119 | + | ||
120 | +SrsAmf0ObjectEOF::SrsAmf0ObjectEOF() | ||
121 | +{ | ||
122 | + utf8_empty = 0x00; | ||
123 | +} | ||
124 | + | ||
125 | +SrsAmf0ObjectEOF::~SrsAmf0ObjectEOF() | ||
126 | +{ | ||
127 | +} | ||
128 | + | ||
129 | +SrsAmf0Object::SrsAmf0Object() | ||
130 | +{ | ||
131 | + marker = RTMP_AMF0_Object; | ||
132 | +} | ||
133 | + | ||
134 | +SrsAmf0Object::~SrsAmf0Object() | ||
135 | +{ | ||
136 | + std::map<std::string, SrsAmf0Any*>::iterator it; | ||
137 | + for (it = properties.begin(); it != properties.end(); ++it) { | ||
138 | + SrsAmf0Any* any = it->second; | ||
139 | + delete any; | ||
140 | + } | ||
141 | + properties.clear(); | ||
142 | +} | ||
143 | + | ||
144 | +SrsAmf0Any* SrsAmf0Object::get_property(std::string name) | ||
145 | +{ | ||
146 | + std::map<std::string, SrsAmf0Any*>::iterator it; | ||
147 | + | ||
148 | + if ((it = properties.find(name)) == properties.end()) { | ||
149 | + return NULL; | ||
150 | + } | ||
151 | + | ||
152 | + return it->second; | ||
153 | +} | ||
154 | + | ||
155 | +SrsAmf0Any* SrsAmf0Object::ensure_property_string(std::string name) | ||
156 | +{ | ||
157 | + SrsAmf0Any* prop = get_property(name); | ||
158 | + | ||
159 | + if (!prop) { | ||
160 | + return NULL; | ||
161 | + } | ||
162 | + | ||
163 | + if (!prop->is_string()) { | ||
164 | + return NULL; | ||
165 | + } | ||
166 | + | ||
167 | + return prop; | ||
168 | +} | ||
169 | + | ||
53 | int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*&); | 170 | int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*&); |
54 | 171 | ||
55 | int srs_amf0_read_utf8(SrsStream* stream, std::string& value) | 172 | int srs_amf0_read_utf8(SrsStream* stream, std::string& value) |
@@ -254,10 +371,12 @@ int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any*& value) | @@ -254,10 +371,12 @@ int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any*& value) | ||
254 | value = p; | 371 | value = p; |
255 | return ret; | 372 | return ret; |
256 | } | 373 | } |
257 | - default: | ||
258 | - value = new SrsAmf0Any(); | ||
259 | - value->marker = stream->read_char(); | 374 | + case RTMP_AMF0_Invalid: |
375 | + default: { | ||
376 | + ret = ERROR_RTMP_AMF0_INVALID; | ||
377 | + srs_error("invalid amf0 message type. marker=%#x, ret=%d", marker, ret); | ||
260 | return ret; | 378 | return ret; |
379 | + } | ||
261 | } | 380 | } |
262 | 381 | ||
263 | return ret; | 382 | return ret; |
@@ -343,91 +462,3 @@ int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value) | @@ -343,91 +462,3 @@ int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value) | ||
343 | 462 | ||
344 | return ret; | 463 | return ret; |
345 | } | 464 | } |
346 | - | ||
347 | -SrsAmf0Any::SrsAmf0Any() | ||
348 | -{ | ||
349 | - marker = RTMP_AMF0_Null; | ||
350 | -} | ||
351 | - | ||
352 | -SrsAmf0Any::~SrsAmf0Any() | ||
353 | -{ | ||
354 | -} | ||
355 | - | ||
356 | -bool SrsAmf0Any::is_string() | ||
357 | -{ | ||
358 | - return marker == RTMP_AMF0_String; | ||
359 | -} | ||
360 | - | ||
361 | -bool SrsAmf0Any::is_boolean() | ||
362 | -{ | ||
363 | - return marker == RTMP_AMF0_Boolean; | ||
364 | -} | ||
365 | - | ||
366 | -bool SrsAmf0Any::is_number() | ||
367 | -{ | ||
368 | - return marker == RTMP_AMF0_Number; | ||
369 | -} | ||
370 | - | ||
371 | -bool SrsAmf0Any::is_object() | ||
372 | -{ | ||
373 | - return marker == RTMP_AMF0_Object; | ||
374 | -} | ||
375 | - | ||
376 | -bool SrsAmf0Any::is_object_eof() | ||
377 | -{ | ||
378 | - return marker == RTMP_AMF0_ObjectEnd; | ||
379 | -} | ||
380 | - | ||
381 | -SrsAmf0String::SrsAmf0String() | ||
382 | -{ | ||
383 | - marker = RTMP_AMF0_String; | ||
384 | -} | ||
385 | - | ||
386 | -SrsAmf0String::~SrsAmf0String() | ||
387 | -{ | ||
388 | -} | ||
389 | - | ||
390 | -SrsAmf0Boolean::SrsAmf0Boolean() | ||
391 | -{ | ||
392 | - marker = RTMP_AMF0_Boolean; | ||
393 | - value = false; | ||
394 | -} | ||
395 | - | ||
396 | -SrsAmf0Boolean::~SrsAmf0Boolean() | ||
397 | -{ | ||
398 | -} | ||
399 | - | ||
400 | -SrsAmf0Number::SrsAmf0Number() | ||
401 | -{ | ||
402 | - marker = RTMP_AMF0_Number; | ||
403 | - value = 0; | ||
404 | -} | ||
405 | - | ||
406 | -SrsAmf0Number::~SrsAmf0Number() | ||
407 | -{ | ||
408 | - marker = RTMP_AMF0_ObjectEnd; | ||
409 | -} | ||
410 | - | ||
411 | -SrsAmf0ObjectEOF::SrsAmf0ObjectEOF() | ||
412 | -{ | ||
413 | - utf8_empty = 0x00; | ||
414 | -} | ||
415 | - | ||
416 | -SrsAmf0ObjectEOF::~SrsAmf0ObjectEOF() | ||
417 | -{ | ||
418 | -} | ||
419 | - | ||
420 | -SrsAmf0Object::SrsAmf0Object() | ||
421 | -{ | ||
422 | - marker = RTMP_AMF0_Object; | ||
423 | -} | ||
424 | - | ||
425 | -SrsAmf0Object::~SrsAmf0Object() | ||
426 | -{ | ||
427 | - std::map<std::string, SrsAmf0Any*>::iterator it; | ||
428 | - for (it = properties.begin(); it != properties.end(); ++it) { | ||
429 | - SrsAmf0Any* any = it->second; | ||
430 | - delete any; | ||
431 | - } | ||
432 | - properties.clear(); | ||
433 | -} |
@@ -37,46 +37,6 @@ class SrsStream; | @@ -37,46 +37,6 @@ class SrsStream; | ||
37 | class SrsAmf0Object; | 37 | class SrsAmf0Object; |
38 | 38 | ||
39 | /** | 39 | /** |
40 | -* read amf0 utf8 string from stream. | ||
41 | -* 1.3.1 Strings and UTF-8 | ||
42 | -* UTF-8 = U16 *(UTF8-char) | ||
43 | -* UTF8-char = UTF8-1 | UTF8-2 | UTF8-3 | UTF8-4 | ||
44 | -* UTF8-1 = %x00-7F | ||
45 | -* @remark only support UTF8-1 char. | ||
46 | -*/ | ||
47 | -extern int srs_amf0_read_utf8(SrsStream* stream, std::string& value); | ||
48 | - | ||
49 | -/** | ||
50 | -* read amf0 string from stream. | ||
51 | -* 2.4 String Type | ||
52 | -* string-type = string-marker UTF-8 | ||
53 | -*/ | ||
54 | -extern int srs_amf0_read_string(SrsStream* stream, std::string& value); | ||
55 | - | ||
56 | -/** | ||
57 | -* read amf0 boolean from stream. | ||
58 | -* 2.4 String Type | ||
59 | -* boolean-type = boolean-marker U8 | ||
60 | -* 0 is false, <> 0 is true | ||
61 | -*/ | ||
62 | -extern int srs_amf0_read_boolean(SrsStream* stream, bool& value); | ||
63 | - | ||
64 | -/** | ||
65 | -* read amf0 number from stream. | ||
66 | -* 2.2 Number Type | ||
67 | -* number-type = number-marker DOUBLE | ||
68 | -*/ | ||
69 | -extern int srs_amf0_read_number(SrsStream* stream, double& value); | ||
70 | - | ||
71 | -/** | ||
72 | -* read amf0 object from stream. | ||
73 | -* 2.5 Object Type | ||
74 | -* anonymous-object-type = object-marker *(object-property) | ||
75 | -* object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker) | ||
76 | -*/ | ||
77 | -extern int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value); | ||
78 | - | ||
79 | -/** | ||
80 | * any amf0 value. | 40 | * any amf0 value. |
81 | * 2.1 Types Overview | 41 | * 2.1 Types Overview |
82 | * value-type = number-type | boolean-type | string-type | object-type | 42 | * value-type = number-type | boolean-type | string-type | object-type |
@@ -166,7 +126,50 @@ struct SrsAmf0Object : public SrsAmf0Any | @@ -166,7 +126,50 @@ struct SrsAmf0Object : public SrsAmf0Any | ||
166 | 126 | ||
167 | SrsAmf0Object(); | 127 | SrsAmf0Object(); |
168 | virtual ~SrsAmf0Object(); | 128 | virtual ~SrsAmf0Object(); |
129 | + | ||
130 | + virtual SrsAmf0Any* get_property(std::string name); | ||
131 | + virtual SrsAmf0Any* ensure_property_string(std::string name); | ||
169 | }; | 132 | }; |
133 | + | ||
134 | +/** | ||
135 | +* read amf0 utf8 string from stream. | ||
136 | +* 1.3.1 Strings and UTF-8 | ||
137 | +* UTF-8 = U16 *(UTF8-char) | ||
138 | +* UTF8-char = UTF8-1 | UTF8-2 | UTF8-3 | UTF8-4 | ||
139 | +* UTF8-1 = %x00-7F | ||
140 | +* @remark only support UTF8-1 char. | ||
141 | +*/ | ||
142 | +extern int srs_amf0_read_utf8(SrsStream* stream, std::string& value); | ||
143 | + | ||
144 | +/** | ||
145 | +* read amf0 string from stream. | ||
146 | +* 2.4 String Type | ||
147 | +* string-type = string-marker UTF-8 | ||
148 | +*/ | ||
149 | +extern int srs_amf0_read_string(SrsStream* stream, std::string& value); | ||
150 | + | ||
151 | +/** | ||
152 | +* read amf0 boolean from stream. | ||
153 | +* 2.4 String Type | ||
154 | +* boolean-type = boolean-marker U8 | ||
155 | +* 0 is false, <> 0 is true | ||
156 | +*/ | ||
157 | +extern int srs_amf0_read_boolean(SrsStream* stream, bool& value); | ||
158 | + | ||
159 | +/** | ||
160 | +* read amf0 number from stream. | ||
161 | +* 2.2 Number Type | ||
162 | +* number-type = number-marker DOUBLE | ||
163 | +*/ | ||
164 | +extern int srs_amf0_read_number(SrsStream* stream, double& value); | ||
165 | + | ||
166 | +/** | ||
167 | +* read amf0 object from stream. | ||
168 | +* 2.5 Object Type | ||
169 | +* anonymous-object-type = object-marker *(object-property) | ||
170 | +* object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker) | ||
171 | +*/ | ||
172 | +extern int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value); | ||
170 | 173 | ||
171 | /** | 174 | /** |
172 | * convert the any to specified object. | 175 | * convert the any to specified object. |
@@ -33,6 +33,7 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd) | @@ -33,6 +33,7 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd) | ||
33 | : SrsConnection(srs_server, client_stfd) | 33 | : SrsConnection(srs_server, client_stfd) |
34 | { | 34 | { |
35 | ip = NULL; | 35 | ip = NULL; |
36 | + req = new SrsRequest(); | ||
36 | rtmp = new SrsRtmp(client_stfd); | 37 | rtmp = new SrsRtmp(client_stfd); |
37 | } | 38 | } |
38 | 39 | ||
@@ -43,6 +44,11 @@ SrsClient::~SrsClient() | @@ -43,6 +44,11 @@ SrsClient::~SrsClient() | ||
43 | ip = NULL; | 44 | ip = NULL; |
44 | } | 45 | } |
45 | 46 | ||
47 | + if (req) { | ||
48 | + delete req; | ||
49 | + req = NULL; | ||
50 | + } | ||
51 | + | ||
46 | if (rtmp) { | 52 | if (rtmp) { |
47 | delete rtmp; | 53 | delete rtmp; |
48 | rtmp = NULL; | 54 | rtmp = NULL; |
@@ -65,12 +71,13 @@ int SrsClient::do_cycle() | @@ -65,12 +71,13 @@ int SrsClient::do_cycle() | ||
65 | } | 71 | } |
66 | srs_verbose("rtmp handshake success"); | 72 | srs_verbose("rtmp handshake success"); |
67 | 73 | ||
68 | - SrsApp* app = NULL; | ||
69 | - if ((ret = rtmp->connect_app(&app)) != ERROR_SUCCESS) { | 74 | + if ((ret = rtmp->connect_app(req)) != ERROR_SUCCESS) { |
70 | srs_warn("rtmp connect vhost/app failed. ret=%d", ret); | 75 | srs_warn("rtmp connect vhost/app failed. ret=%d", ret); |
71 | return ret; | 76 | return ret; |
72 | } | 77 | } |
73 | - srs_verbose("rtmp connect vhost/app success"); | 78 | + srs_info("rtmp connect success. tcUrl=%s, schema=%s, vhost=%s, port=%s, app=%s", |
79 | + req->tcUrl.c_str(), req->schema.c_str(), req->vhost.c_str(), req->port.c_str(), | ||
80 | + req->app.c_str()); | ||
74 | 81 | ||
75 | return ret; | 82 | return ret; |
76 | } | 83 | } |
@@ -33,6 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -33,6 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
33 | #include <srs_core_conn.hpp> | 33 | #include <srs_core_conn.hpp> |
34 | 34 | ||
35 | class SrsRtmp; | 35 | class SrsRtmp; |
36 | +class SrsRequest; | ||
36 | 37 | ||
37 | /** | 38 | /** |
38 | * the client provides the main logic control for RTMP clients. | 39 | * the client provides the main logic control for RTMP clients. |
@@ -41,6 +42,7 @@ class SrsClient : public SrsConnection | @@ -41,6 +42,7 @@ class SrsClient : public SrsConnection | ||
41 | { | 42 | { |
42 | private: | 43 | private: |
43 | char* ip; | 44 | char* ip; |
45 | + SrsRequest* req; | ||
44 | SrsRtmp* rtmp; | 46 | SrsRtmp* rtmp; |
45 | public: | 47 | public: |
46 | SrsClient(SrsServer* srs_server, st_netfd_t client_stfd); | 48 | SrsClient(SrsServer* srs_server, st_netfd_t client_stfd); |
@@ -53,6 +53,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -53,6 +53,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
53 | #define ERROR_RTMP_CHUNK_START 301 | 53 | #define ERROR_RTMP_CHUNK_START 301 |
54 | #define ERROR_RTMP_MSG_INVLIAD_SIZE 302 | 54 | #define ERROR_RTMP_MSG_INVLIAD_SIZE 302 |
55 | #define ERROR_RTMP_AMF0_DECODE 303 | 55 | #define ERROR_RTMP_AMF0_DECODE 303 |
56 | +#define ERROR_RTMP_AMF0_INVALID 304 | ||
57 | +#define ERROR_RTMP_REQ_CONNECT 305 | ||
56 | 58 | ||
57 | #define ERROR_SYSTEM_STREAM_INIT 400 | 59 | #define ERROR_SYSTEM_STREAM_INIT 400 |
58 | 60 |
@@ -194,190 +194,6 @@ messages. | @@ -194,190 +194,6 @@ messages. | ||
194 | */ | 194 | */ |
195 | #define RTMP_AMF0_COMMAND_CONNECT "connect" | 195 | #define RTMP_AMF0_COMMAND_CONNECT "connect" |
196 | 196 | ||
197 | -SrsMessageHeader::SrsMessageHeader() | ||
198 | -{ | ||
199 | - message_type = 0; | ||
200 | - payload_length = 0; | ||
201 | - timestamp = 0; | ||
202 | - stream_id = 0; | ||
203 | -} | ||
204 | - | ||
205 | -SrsMessageHeader::~SrsMessageHeader() | ||
206 | -{ | ||
207 | -} | ||
208 | - | ||
209 | -SrsChunkStream::SrsChunkStream(int _cid) | ||
210 | -{ | ||
211 | - fmt = 0; | ||
212 | - cid = _cid; | ||
213 | - extended_timestamp = false; | ||
214 | - msg = NULL; | ||
215 | -} | ||
216 | - | ||
217 | -SrsChunkStream::~SrsChunkStream() | ||
218 | -{ | ||
219 | - if (msg) { | ||
220 | - delete msg; | ||
221 | - msg = NULL; | ||
222 | - } | ||
223 | -} | ||
224 | - | ||
225 | -SrsMessage::SrsMessage() | ||
226 | -{ | ||
227 | - size = 0; | ||
228 | - stream = NULL; | ||
229 | - payload = NULL; | ||
230 | - decoded_payload = NULL; | ||
231 | -} | ||
232 | - | ||
233 | -SrsMessage::~SrsMessage() | ||
234 | -{ | ||
235 | - if (payload) { | ||
236 | - delete[] payload; | ||
237 | - payload = NULL; | ||
238 | - } | ||
239 | - | ||
240 | - if (decoded_payload) { | ||
241 | - delete decoded_payload; | ||
242 | - decoded_payload = NULL; | ||
243 | - } | ||
244 | - | ||
245 | - if (stream) { | ||
246 | - delete stream; | ||
247 | - stream = NULL; | ||
248 | - } | ||
249 | -} | ||
250 | - | ||
251 | -SrsPacket* SrsMessage::get_packet() | ||
252 | -{ | ||
253 | - if (!decoded_payload) { | ||
254 | - srs_error("the payload is raw/undecoded, invoke decode_packet to decode it."); | ||
255 | - } | ||
256 | - srs_assert(decoded_payload != NULL); | ||
257 | - | ||
258 | - return decoded_payload; | ||
259 | -} | ||
260 | - | ||
261 | -int SrsMessage::decode_packet() | ||
262 | -{ | ||
263 | - int ret = ERROR_SUCCESS; | ||
264 | - | ||
265 | - srs_assert(payload != NULL); | ||
266 | - srs_assert(size > 0); | ||
267 | - | ||
268 | - if (!stream) { | ||
269 | - srs_verbose("create decode stream for message."); | ||
270 | - stream = new SrsStream(); | ||
271 | - } | ||
272 | - | ||
273 | - if (header.message_type == RTMP_MSG_AMF0CommandMessage) { | ||
274 | - srs_verbose("start to decode AMF0 command message."); | ||
275 | - | ||
276 | - // amf0 command message. | ||
277 | - // need to read the command name. | ||
278 | - if ((ret = stream->initialize((char*)payload, size)) != ERROR_SUCCESS) { | ||
279 | - srs_error("initialize stream failed. ret=%d", ret); | ||
280 | - return ret; | ||
281 | - } | ||
282 | - srs_verbose("decode stream initialized success"); | ||
283 | - | ||
284 | - std::string command; | ||
285 | - if ((ret = srs_amf0_read_string(stream, command)) != ERROR_SUCCESS) { | ||
286 | - srs_error("decode AMF0 command name failed. ret=%d", ret); | ||
287 | - return ret; | ||
288 | - } | ||
289 | - srs_verbose("AMF0 command message, command_name=%s", command.c_str()); | ||
290 | - | ||
291 | - stream->reset(); | ||
292 | - if (command == RTMP_AMF0_COMMAND_CONNECT) { | ||
293 | - srs_info("decode the AMF0 command(connect vhost/app message)."); | ||
294 | - decoded_payload = new SrsConnectAppPacket(); | ||
295 | - return decoded_payload->decode(stream); | ||
296 | - } | ||
297 | - | ||
298 | - // default packet to drop message. | ||
299 | - srs_trace("drop the AMF0 command message, command_name=%s", command.c_str()); | ||
300 | - decoded_payload = new SrsPacket(); | ||
301 | - return ret; | ||
302 | - } | ||
303 | - | ||
304 | - // default packet to drop message. | ||
305 | - srs_trace("drop the unknown message, type=%d", header.message_type); | ||
306 | - decoded_payload = new SrsPacket(); | ||
307 | - | ||
308 | - return ret; | ||
309 | -} | ||
310 | - | ||
311 | -SrsPacket::SrsPacket() | ||
312 | -{ | ||
313 | -} | ||
314 | - | ||
315 | -SrsPacket::~SrsPacket() | ||
316 | -{ | ||
317 | -} | ||
318 | - | ||
319 | -int SrsPacket::decode(SrsStream* /*stream*/) | ||
320 | -{ | ||
321 | - int ret = ERROR_SUCCESS; | ||
322 | - return ret; | ||
323 | -} | ||
324 | - | ||
325 | -SrsConnectAppPacket::SrsConnectAppPacket() | ||
326 | -{ | ||
327 | - command_name = RTMP_AMF0_COMMAND_CONNECT; | ||
328 | - transaction_id = 1; | ||
329 | - command_object = NULL; | ||
330 | -} | ||
331 | - | ||
332 | -SrsConnectAppPacket::~SrsConnectAppPacket() | ||
333 | -{ | ||
334 | -} | ||
335 | - | ||
336 | -int SrsConnectAppPacket::decode(SrsStream* stream) | ||
337 | -{ | ||
338 | - int ret = ERROR_SUCCESS; | ||
339 | - | ||
340 | - if ((ret = super::decode(stream)) != ERROR_SUCCESS) { | ||
341 | - return ret; | ||
342 | - } | ||
343 | - | ||
344 | - if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) { | ||
345 | - srs_error("amf0 decode connect command_name failed. ret=%d", ret); | ||
346 | - return ret; | ||
347 | - } | ||
348 | - if (command_name.empty() || command_name != RTMP_AMF0_COMMAND_CONNECT) { | ||
349 | - ret = ERROR_RTMP_AMF0_DECODE; | ||
350 | - srs_error("amf0 decode connect command_name failed. " | ||
351 | - "command_name=%s, ret=%d", command_name.c_str(), ret); | ||
352 | - return ret; | ||
353 | - } | ||
354 | - | ||
355 | - if ((ret = srs_amf0_read_number(stream, transaction_id)) != ERROR_SUCCESS) { | ||
356 | - srs_error("amf0 decode connect transaction_id failed. ret=%d", ret); | ||
357 | - return ret; | ||
358 | - } | ||
359 | - if (transaction_id != 1.0) { | ||
360 | - ret = ERROR_RTMP_AMF0_DECODE; | ||
361 | - srs_error("amf0 decode connect transaction_id failed. " | ||
362 | - "required=%.1f, actual=%.1f, ret=%d", 1.0, transaction_id, ret); | ||
363 | - return ret; | ||
364 | - } | ||
365 | - | ||
366 | - if ((ret = srs_amf0_read_object(stream, command_object)) != ERROR_SUCCESS) { | ||
367 | - srs_error("amf0 decode connect command_object failed. ret=%d", ret); | ||
368 | - return ret; | ||
369 | - } | ||
370 | - if (command_object == NULL) { | ||
371 | - ret = ERROR_RTMP_AMF0_DECODE; | ||
372 | - srs_error("amf0 decode connect command_object failed. ret=%d", ret); | ||
373 | - return ret; | ||
374 | - } | ||
375 | - | ||
376 | - srs_info("amf0 decode connect packet success"); | ||
377 | - | ||
378 | - return ret; | ||
379 | -} | ||
380 | - | ||
381 | SrsProtocol::SrsProtocol(st_netfd_t client_stfd) | 197 | SrsProtocol::SrsProtocol(st_netfd_t client_stfd) |
382 | { | 198 | { |
383 | stfd = client_stfd; | 199 | stfd = client_stfd; |
@@ -771,3 +587,187 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh | @@ -771,3 +587,187 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh | ||
771 | return ret; | 587 | return ret; |
772 | } | 588 | } |
773 | 589 | ||
590 | +SrsMessageHeader::SrsMessageHeader() | ||
591 | +{ | ||
592 | + message_type = 0; | ||
593 | + payload_length = 0; | ||
594 | + timestamp = 0; | ||
595 | + stream_id = 0; | ||
596 | +} | ||
597 | + | ||
598 | +SrsMessageHeader::~SrsMessageHeader() | ||
599 | +{ | ||
600 | +} | ||
601 | + | ||
602 | +SrsChunkStream::SrsChunkStream(int _cid) | ||
603 | +{ | ||
604 | + fmt = 0; | ||
605 | + cid = _cid; | ||
606 | + extended_timestamp = false; | ||
607 | + msg = NULL; | ||
608 | +} | ||
609 | + | ||
610 | +SrsChunkStream::~SrsChunkStream() | ||
611 | +{ | ||
612 | + if (msg) { | ||
613 | + delete msg; | ||
614 | + msg = NULL; | ||
615 | + } | ||
616 | +} | ||
617 | + | ||
618 | +SrsMessage::SrsMessage() | ||
619 | +{ | ||
620 | + size = 0; | ||
621 | + stream = NULL; | ||
622 | + payload = NULL; | ||
623 | + decoded_payload = NULL; | ||
624 | +} | ||
625 | + | ||
626 | +SrsMessage::~SrsMessage() | ||
627 | +{ | ||
628 | + if (payload) { | ||
629 | + delete[] payload; | ||
630 | + payload = NULL; | ||
631 | + } | ||
632 | + | ||
633 | + if (decoded_payload) { | ||
634 | + delete decoded_payload; | ||
635 | + decoded_payload = NULL; | ||
636 | + } | ||
637 | + | ||
638 | + if (stream) { | ||
639 | + delete stream; | ||
640 | + stream = NULL; | ||
641 | + } | ||
642 | +} | ||
643 | + | ||
644 | +SrsPacket* SrsMessage::get_packet() | ||
645 | +{ | ||
646 | + if (!decoded_payload) { | ||
647 | + srs_error("the payload is raw/undecoded, invoke decode_packet to decode it."); | ||
648 | + } | ||
649 | + srs_assert(decoded_payload != NULL); | ||
650 | + | ||
651 | + return decoded_payload; | ||
652 | +} | ||
653 | + | ||
654 | +int SrsMessage::decode_packet() | ||
655 | +{ | ||
656 | + int ret = ERROR_SUCCESS; | ||
657 | + | ||
658 | + srs_assert(payload != NULL); | ||
659 | + srs_assert(size > 0); | ||
660 | + | ||
661 | + if (!stream) { | ||
662 | + srs_verbose("create decode stream for message."); | ||
663 | + stream = new SrsStream(); | ||
664 | + } | ||
665 | + | ||
666 | + if (header.message_type == RTMP_MSG_AMF0CommandMessage) { | ||
667 | + srs_verbose("start to decode AMF0 command message."); | ||
668 | + | ||
669 | + // amf0 command message. | ||
670 | + // need to read the command name. | ||
671 | + if ((ret = stream->initialize((char*)payload, size)) != ERROR_SUCCESS) { | ||
672 | + srs_error("initialize stream failed. ret=%d", ret); | ||
673 | + return ret; | ||
674 | + } | ||
675 | + srs_verbose("decode stream initialized success"); | ||
676 | + | ||
677 | + std::string command; | ||
678 | + if ((ret = srs_amf0_read_string(stream, command)) != ERROR_SUCCESS) { | ||
679 | + srs_error("decode AMF0 command name failed. ret=%d", ret); | ||
680 | + return ret; | ||
681 | + } | ||
682 | + srs_verbose("AMF0 command message, command_name=%s", command.c_str()); | ||
683 | + | ||
684 | + stream->reset(); | ||
685 | + if (command == RTMP_AMF0_COMMAND_CONNECT) { | ||
686 | + srs_info("decode the AMF0 command(connect vhost/app message)."); | ||
687 | + decoded_payload = new SrsConnectAppPacket(); | ||
688 | + return decoded_payload->decode(stream); | ||
689 | + } | ||
690 | + | ||
691 | + // default packet to drop message. | ||
692 | + srs_trace("drop the AMF0 command message, command_name=%s", command.c_str()); | ||
693 | + decoded_payload = new SrsPacket(); | ||
694 | + return ret; | ||
695 | + } | ||
696 | + | ||
697 | + // default packet to drop message. | ||
698 | + srs_trace("drop the unknown message, type=%d", header.message_type); | ||
699 | + decoded_payload = new SrsPacket(); | ||
700 | + | ||
701 | + return ret; | ||
702 | +} | ||
703 | + | ||
704 | +SrsPacket::SrsPacket() | ||
705 | +{ | ||
706 | +} | ||
707 | + | ||
708 | +SrsPacket::~SrsPacket() | ||
709 | +{ | ||
710 | +} | ||
711 | + | ||
712 | +int SrsPacket::decode(SrsStream* /*stream*/) | ||
713 | +{ | ||
714 | + int ret = ERROR_SUCCESS; | ||
715 | + return ret; | ||
716 | +} | ||
717 | + | ||
718 | +SrsConnectAppPacket::SrsConnectAppPacket() | ||
719 | +{ | ||
720 | + command_name = RTMP_AMF0_COMMAND_CONNECT; | ||
721 | + transaction_id = 1; | ||
722 | + command_object = NULL; | ||
723 | +} | ||
724 | + | ||
725 | +SrsConnectAppPacket::~SrsConnectAppPacket() | ||
726 | +{ | ||
727 | +} | ||
728 | + | ||
729 | +int SrsConnectAppPacket::decode(SrsStream* stream) | ||
730 | +{ | ||
731 | + int ret = ERROR_SUCCESS; | ||
732 | + | ||
733 | + if ((ret = super::decode(stream)) != ERROR_SUCCESS) { | ||
734 | + return ret; | ||
735 | + } | ||
736 | + | ||
737 | + if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) { | ||
738 | + srs_error("amf0 decode connect command_name failed. ret=%d", ret); | ||
739 | + return ret; | ||
740 | + } | ||
741 | + if (command_name.empty() || command_name != RTMP_AMF0_COMMAND_CONNECT) { | ||
742 | + ret = ERROR_RTMP_AMF0_DECODE; | ||
743 | + srs_error("amf0 decode connect command_name failed. " | ||
744 | + "command_name=%s, ret=%d", command_name.c_str(), ret); | ||
745 | + return ret; | ||
746 | + } | ||
747 | + | ||
748 | + if ((ret = srs_amf0_read_number(stream, transaction_id)) != ERROR_SUCCESS) { | ||
749 | + srs_error("amf0 decode connect transaction_id failed. ret=%d", ret); | ||
750 | + return ret; | ||
751 | + } | ||
752 | + if (transaction_id != 1.0) { | ||
753 | + ret = ERROR_RTMP_AMF0_DECODE; | ||
754 | + srs_error("amf0 decode connect transaction_id failed. " | ||
755 | + "required=%.1f, actual=%.1f, ret=%d", 1.0, transaction_id, ret); | ||
756 | + return ret; | ||
757 | + } | ||
758 | + | ||
759 | + if ((ret = srs_amf0_read_object(stream, command_object)) != ERROR_SUCCESS) { | ||
760 | + srs_error("amf0 decode connect command_object failed. ret=%d", ret); | ||
761 | + return ret; | ||
762 | + } | ||
763 | + if (command_object == NULL) { | ||
764 | + ret = ERROR_RTMP_AMF0_DECODE; | ||
765 | + srs_error("amf0 decode connect command_object failed. ret=%d", ret); | ||
766 | + return ret; | ||
767 | + } | ||
768 | + | ||
769 | + srs_info("amf0 decode connect packet success"); | ||
770 | + | ||
771 | + return ret; | ||
772 | +} | ||
773 | + |
@@ -47,6 +47,39 @@ class SrsChunkStream; | @@ -47,6 +47,39 @@ class SrsChunkStream; | ||
47 | class SrsAmf0Object; | 47 | class SrsAmf0Object; |
48 | 48 | ||
49 | /** | 49 | /** |
50 | +* the protocol provides the rtmp-message-protocol services, | ||
51 | +* to recv RTMP message from RTMP chunk stream, | ||
52 | +* and to send out RTMP message over RTMP chunk stream. | ||
53 | +*/ | ||
54 | +class SrsProtocol | ||
55 | +{ | ||
56 | +private: | ||
57 | + std::map<int, SrsChunkStream*> chunk_streams; | ||
58 | + st_netfd_t stfd; | ||
59 | + SrsBuffer* buffer; | ||
60 | + SrsSocket* skt; | ||
61 | + int32_t in_chunk_size; | ||
62 | + int32_t out_chunk_size; | ||
63 | +public: | ||
64 | + SrsProtocol(st_netfd_t client_stfd); | ||
65 | + virtual ~SrsProtocol(); | ||
66 | +public: | ||
67 | + /** | ||
68 | + * recv a message with raw/undecoded payload from peer. | ||
69 | + * the payload is not decoded, use srs_rtmp_expect_message<T> if requires | ||
70 | + * specifies message. | ||
71 | + * @pmsg, user must free it. NULL if not success. | ||
72 | + * @remark, only when success, user can use and must free the pmsg. | ||
73 | + */ | ||
74 | + virtual int recv_message(SrsMessage** pmsg); | ||
75 | +private: | ||
76 | + virtual int recv_interlaced_message(SrsMessage** pmsg); | ||
77 | + virtual int read_basic_header(char& fmt, int& cid, int& size); | ||
78 | + virtual int read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size); | ||
79 | + virtual int read_message_payload(SrsChunkStream* chunk, int bh_size, int mh_size, int& payload_size, SrsMessage** pmsg); | ||
80 | +}; | ||
81 | + | ||
82 | +/** | ||
50 | * 4.1. Message Header | 83 | * 4.1. Message Header |
51 | */ | 84 | */ |
52 | struct SrsMessageHeader | 85 | struct SrsMessageHeader |
@@ -162,7 +195,7 @@ class SrsConnectAppPacket : public SrsPacket | @@ -162,7 +195,7 @@ class SrsConnectAppPacket : public SrsPacket | ||
162 | { | 195 | { |
163 | private: | 196 | private: |
164 | typedef SrsPacket super; | 197 | typedef SrsPacket super; |
165 | -private: | 198 | +public: |
166 | std::string command_name; | 199 | std::string command_name; |
167 | double transaction_id; | 200 | double transaction_id; |
168 | SrsAmf0Object* command_object; | 201 | SrsAmf0Object* command_object; |
@@ -174,80 +207,48 @@ public: | @@ -174,80 +207,48 @@ public: | ||
174 | }; | 207 | }; |
175 | 208 | ||
176 | /** | 209 | /** |
177 | -* the protocol provides the rtmp-message-protocol services, | ||
178 | -* to recv RTMP message from RTMP chunk stream, | ||
179 | -* and to send out RTMP message over RTMP chunk stream. | 210 | +* expect a specified message, drop others util got specified one. |
211 | +* @pmsg, user must free it. NULL if not success. | ||
212 | +* @ppacket, store in the pmsg, user must never free it. NULL if not success. | ||
213 | +* @remark, only when success, user can use and must free the pmsg/ppacket. | ||
180 | */ | 214 | */ |
181 | -class SrsProtocol | 215 | +template<class T> |
216 | +int srs_rtmp_expect_message(SrsProtocol* protocol, SrsMessage** pmsg, T** ppacket) | ||
182 | { | 217 | { |
183 | -private: | ||
184 | - std::map<int, SrsChunkStream*> chunk_streams; | ||
185 | - st_netfd_t stfd; | ||
186 | - SrsBuffer* buffer; | ||
187 | - SrsSocket* skt; | ||
188 | - int32_t in_chunk_size; | ||
189 | - int32_t out_chunk_size; | ||
190 | -public: | ||
191 | - SrsProtocol(st_netfd_t client_stfd); | ||
192 | - virtual ~SrsProtocol(); | ||
193 | -public: | ||
194 | - /** | ||
195 | - * recv a message with raw/undecoded payload from peer. | ||
196 | - * the payload is not decoded, use expect_message<T> if requires specifies message. | ||
197 | - * @pmsg, user must free it. NULL if not success. | ||
198 | - * @remark, only when success, user can use and must free the pmsg. | ||
199 | - */ | ||
200 | - virtual int recv_message(SrsMessage** pmsg); | ||
201 | -public: | ||
202 | - /** | ||
203 | - * expect a specified message, drop others util got specified one. | ||
204 | - * @pmsg, user must free it. NULL if not success. | ||
205 | - * @ppacket, store in the pmsg, user must never free it. NULL if not success. | ||
206 | - * @remark, only when success, user can use and must free the pmsg/ppacket. | ||
207 | - */ | ||
208 | - template<class T> | ||
209 | - int expect_message(SrsMessage** pmsg, T** ppacket) | ||
210 | - { | ||
211 | - *pmsg = NULL; | ||
212 | - *ppacket = NULL; | 218 | + *pmsg = NULL; |
219 | + *ppacket = NULL; | ||
220 | + | ||
221 | + int ret = ERROR_SUCCESS; | ||
222 | + | ||
223 | + while (true) { | ||
224 | + SrsMessage* msg = NULL; | ||
225 | + if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { | ||
226 | + srs_error("recv message failed. ret=%d", ret); | ||
227 | + return ret; | ||
228 | + } | ||
229 | + srs_verbose("recv message success."); | ||
213 | 230 | ||
214 | - int ret = ERROR_SUCCESS; | 231 | + if ((ret = msg->decode_packet()) != ERROR_SUCCESS) { |
232 | + delete msg; | ||
233 | + srs_error("decode message failed. ret=%d", ret); | ||
234 | + return ret; | ||
235 | + } | ||
215 | 236 | ||
216 | - while (true) { | ||
217 | - SrsMessage* msg = NULL; | ||
218 | - if ((ret = recv_message(&msg)) != ERROR_SUCCESS) { | ||
219 | - srs_error("recv message failed. ret=%d", ret); | ||
220 | - return ret; | ||
221 | - } | ||
222 | - srs_verbose("recv message success."); | ||
223 | - | ||
224 | - if ((ret = msg->decode_packet()) != ERROR_SUCCESS) { | ||
225 | - delete msg; | ||
226 | - srs_error("decode message failed. ret=%d", ret); | ||
227 | - return ret; | ||
228 | - } | ||
229 | - | ||
230 | - T* pkt = dynamic_cast<T*>(msg->get_packet()); | ||
231 | - if (!pkt) { | ||
232 | - delete msg; | ||
233 | - srs_trace("drop message(type=%d, size=%d, time=%d, sid=%d).", | ||
234 | - msg->header.message_type, msg->header.payload_length, | ||
235 | - msg->header.timestamp, msg->header.stream_id); | ||
236 | - continue; | ||
237 | - } | ||
238 | - | ||
239 | - *pmsg = msg; | ||
240 | - *ppacket = pkt; | ||
241 | - break; | 237 | + T* pkt = dynamic_cast<T*>(msg->get_packet()); |
238 | + if (!pkt) { | ||
239 | + delete msg; | ||
240 | + srs_trace("drop message(type=%d, size=%d, time=%d, sid=%d).", | ||
241 | + msg->header.message_type, msg->header.payload_length, | ||
242 | + msg->header.timestamp, msg->header.stream_id); | ||
243 | + continue; | ||
242 | } | 244 | } |
243 | 245 | ||
244 | - return ret; | 246 | + *pmsg = msg; |
247 | + *ppacket = pkt; | ||
248 | + break; | ||
245 | } | 249 | } |
246 | -private: | ||
247 | - virtual int recv_interlaced_message(SrsMessage** pmsg); | ||
248 | - virtual int read_basic_header(char& fmt, int& cid, int& size); | ||
249 | - virtual int read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size); | ||
250 | - virtual int read_message_payload(SrsChunkStream* chunk, int bh_size, int mh_size, int& payload_size, SrsMessage** pmsg); | ||
251 | -}; | 250 | + |
251 | + return ret; | ||
252 | +} | ||
252 | 253 | ||
253 | #endif | 254 | #endif |
@@ -28,6 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -28,6 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
28 | #include <srs_core_socket.hpp> | 28 | #include <srs_core_socket.hpp> |
29 | #include <srs_core_protocol.hpp> | 29 | #include <srs_core_protocol.hpp> |
30 | #include <srs_core_auto_free.hpp> | 30 | #include <srs_core_auto_free.hpp> |
31 | +#include <srs_core_amf0.hpp> | ||
31 | 32 | ||
32 | SrsRtmp::SrsRtmp(st_netfd_t client_stfd) | 33 | SrsRtmp::SrsRtmp(st_netfd_t client_stfd) |
33 | { | 34 | { |
@@ -89,19 +90,28 @@ int SrsRtmp::handshake() | @@ -89,19 +90,28 @@ int SrsRtmp::handshake() | ||
89 | return ret; | 90 | return ret; |
90 | } | 91 | } |
91 | 92 | ||
92 | -int SrsRtmp::connect_app(SrsApp** papp) | 93 | +int SrsRtmp::connect_app(SrsRequest* req) |
93 | { | 94 | { |
94 | int ret = ERROR_SUCCESS; | 95 | int ret = ERROR_SUCCESS; |
95 | 96 | ||
96 | SrsMessage* msg = NULL; | 97 | SrsMessage* msg = NULL; |
97 | SrsConnectAppPacket* pkt = NULL; | 98 | SrsConnectAppPacket* pkt = NULL; |
98 | - if ((ret = protocol->expect_message<SrsConnectAppPacket>(&msg, &pkt)) != ERROR_SUCCESS) { | 99 | + if ((ret = srs_rtmp_expect_message<SrsConnectAppPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) { |
99 | srs_error("expect connect app message failed. ret=%d", ret); | 100 | srs_error("expect connect app message failed. ret=%d", ret); |
100 | return ret; | 101 | return ret; |
101 | } | 102 | } |
102 | SrsAutoFree(SrsMessage, msg, false); | 103 | SrsAutoFree(SrsMessage, msg, false); |
103 | srs_info("get connect app message"); | 104 | srs_info("get connect app message"); |
104 | 105 | ||
106 | + SrsAmf0Any* prop = NULL; | ||
107 | + | ||
108 | + if ((prop = pkt->command_object->ensure_property_string("tcUrl")) == NULL) { | ||
109 | + ret = ERROR_RTMP_REQ_CONNECT; | ||
110 | + srs_error("invalid request, must specifies the tcUrl. ret=%d", ret); | ||
111 | + return ret; | ||
112 | + } | ||
113 | + req->tcUrl = srs_amf0_convert<SrsAmf0String>(prop)->value; | ||
114 | + | ||
105 | return ret; | 115 | return ret; |
106 | } | 116 | } |
107 | 117 |
@@ -36,10 +36,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -36,10 +36,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
36 | 36 | ||
37 | class SrsProtocol; | 37 | class SrsProtocol; |
38 | 38 | ||
39 | -struct SrsApp | 39 | +/** |
40 | +* the original request from client. | ||
41 | +*/ | ||
42 | +struct SrsRequest | ||
40 | { | 43 | { |
44 | + std::string tcUrl; | ||
45 | + | ||
46 | + std::string schema; | ||
41 | std::string vhost; | 47 | std::string vhost; |
48 | + std::string port; | ||
42 | std::string app; | 49 | std::string app; |
50 | + std::string stream; | ||
43 | }; | 51 | }; |
44 | 52 | ||
45 | /** | 53 | /** |
@@ -57,7 +65,7 @@ public: | @@ -57,7 +65,7 @@ public: | ||
57 | virtual ~SrsRtmp(); | 65 | virtual ~SrsRtmp(); |
58 | public: | 66 | public: |
59 | virtual int handshake(); | 67 | virtual int handshake(); |
60 | - virtual int connect_app(SrsApp** papp); | 68 | + virtual int connect_app(SrsRequest* req); |
61 | }; | 69 | }; |
62 | 70 | ||
63 | #endif | 71 | #endif |
-
请 注册 或 登录 后发表评论