diff --git a/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp b/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp index 9238425ad..9038814d4 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp +++ b/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp @@ -868,6 +868,50 @@ int SrsProtocol::recv_interlaced_message(SrsMessage** pmsg) return ret; } +/** +* 6.1.1. Chunk Basic Header +* The Chunk Basic Header encodes the chunk stream ID and the chunk +* type(represented by fmt field in the figure below). Chunk type +* determines the format of the encoded message header. Chunk Basic +* Header field may be 1, 2, or 3 bytes, depending on the chunk stream +* ID. +* +* The bits 0–5 (least significant) in the chunk basic header represent +* the chunk stream ID. +* +* Chunk stream IDs 2-63 can be encoded in the 1-byte version of this +* field. +* 0 1 2 3 4 5 6 7 +* +-+-+-+-+-+-+-+-+ +* |fmt| cs id | +* +-+-+-+-+-+-+-+-+ +* Figure 6 Chunk basic header 1 +* +* Chunk stream IDs 64-319 can be encoded in the 2-byte version of this +* field. ID is computed as (the second byte + 64). +* 0 1 +* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* |fmt| 0 | cs id - 64 | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* Figure 7 Chunk basic header 2 +* +* Chunk stream IDs 64-65599 can be encoded in the 3-byte version of +* this field. ID is computed as ((the third byte)*256 + the second byte +* + 64). +* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* |fmt| 1 | cs id - 64 | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* Figure 8 Chunk basic header 3 +* +* cs id: 6 bits +* fmt: 2 bits +* cs id - 64: 8 or 16 bits +* +* Chunk stream IDs with values 64-319 could be represented by both 2- +* byte version and 3-byte version of this field. +*/ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& bh_size) { int ret = ERROR_SUCCESS; @@ -886,11 +930,13 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& bh_size) cid = *p & 0x3f; bh_size = 1; + // 2-63, 1B chunk header if (cid > 1) { srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", bh_size, fmt, cid); return ret; } + // 64-319, 2B chunk header if (cid == 0) { required_size = 2; if ((ret = in_buffer->grow(skt, required_size)) != ERROR_SUCCESS) { @@ -901,9 +947,10 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& bh_size) } cid = 64; - cid += *(++p); + cid += (u_int8_t)*(++p); bh_size = 2; srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", bh_size, fmt, cid); + // 64-65599, 3B chunk header } else if (cid == 1) { required_size = 3; if ((ret = in_buffer->grow(skt, 3)) != ERROR_SUCCESS) { @@ -914,8 +961,8 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& bh_size) } cid = 64; - cid += *(++p); - cid += *(++p) * 256; + cid += (u_int8_t)*(++p); + cid += ((u_int8_t)*(++p)) * 256; bh_size = 3; srs_verbose("%dbytes basic header parsed. fmt=%d, cid=%d", bh_size, fmt, cid); } else { @@ -926,6 +973,18 @@ int SrsProtocol::read_basic_header(char& fmt, int& cid, int& bh_size) return ret; } +/** +* parse the message header. +* 3bytes: timestamp delta, fmt=0,1,2 +* 3bytes: payload length, fmt=0,1 +* 1bytes: message type, fmt=0,1 +* 4bytes: stream id, fmt=0 +* where: +* fmt=0, 0x0X +* fmt=1, 0x4X +* fmt=2, 0x8X +* fmt=3, 0xCX +*/ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size) { int ret = ERROR_SUCCESS; diff --git a/trunk/src/utest/srs_utest_protocol.cpp b/trunk/src/utest/srs_utest_protocol.cpp index a03bcf60a..f9146d004 100644 --- a/trunk/src/utest/srs_utest_protocol.cpp +++ b/trunk/src/utest/srs_utest_protocol.cpp @@ -401,6 +401,9 @@ VOID TEST(ProtocolHandshakeTest, ComplexHandshake) } } +/** +* bytes equal utility +*/ VOID TEST(ProtocolHandshakeTest, BytesEqual) { char a1[] = { (char)0x01 }; @@ -417,6 +420,9 @@ VOID TEST(ProtocolHandshakeTest, BytesEqual) EXPECT_FALSE(srs_bytes_equals(a1, b2, 1)); } +/** +* resolve vhost from tcUrl. +*/ VOID TEST(ProtocolUtilityTest, VhostResolve) { std::string vhost = "vhost"; @@ -446,6 +452,9 @@ VOID TEST(ProtocolUtilityTest, VhostResolve) EXPECT_STREQ("app", app.c_str()); } +/** +* discovery tcUrl to schema/vhost/host/port/app +*/ VOID TEST(ProtocolUtilityTest, DiscoveryTcUrl) { std::string tcUrl; @@ -485,6 +494,9 @@ VOID TEST(ProtocolUtilityTest, DiscoveryTcUrl) EXPECT_STREQ("19351", port.c_str()); } +/** +* generate tcUrl from ip/vhost/app/port +*/ VOID TEST(ProtocolUtilityTest, GenerateTcUrl) { string ip; string vhost; string app; string port; string tcUrl; @@ -502,6 +514,9 @@ VOID TEST(ProtocolUtilityTest, GenerateTcUrl) EXPECT_STREQ("rtmp://demo:19351/live", tcUrl.c_str()); } +/** +* shared ptr message array test +*/ VOID TEST(ProtocolMsgArrayTest, MessageArray) { SrsMessageHeader header; @@ -536,6 +551,9 @@ VOID TEST(ProtocolMsgArrayTest, MessageArray) EXPECT_EQ(0, msg.count()); } +/** +* set/get timeout of protocol stack +*/ VOID TEST(ProtocolStackTest, ProtocolTimeout) { MockBufferIO bio; @@ -551,6 +569,9 @@ VOID TEST(ProtocolStackTest, ProtocolTimeout) EXPECT_TRUE(10 == proto.get_send_timeout()); } +/** +* get recv/send bytes of protocol stack. +*/ VOID TEST(ProtocolStackTest, ProtocolBytes) { MockBufferIO bio; @@ -564,6 +585,9 @@ VOID TEST(ProtocolStackTest, ProtocolBytes) EXPECT_TRUE(0 < proto.get_send_bytes()); } +/** +* recv a SrsConnectAppPacket packet. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvMessage) { MockBufferIO bio; @@ -657,6 +681,9 @@ VOID TEST(ProtocolStackTest, ProtocolRecvMessageBug98) EXPECT_EQ(0x0d0f, spkt->event_data); } +/** +* recv a SrsSetWindowAckSizePacket packet. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvAckSizeMessage) { MockBufferIO bio; @@ -688,6 +715,9 @@ VOID TEST(ProtocolStackTest, ProtocolRecvAckSizeMessage) EXPECT_EQ(0x0763, spkt->ackowledgement_window_size); } +/** +* recv a video message. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVMessage) { MockBufferIO bio; @@ -712,6 +742,9 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVMessage) EXPECT_TRUE(msg->header.is_video()); } +/** +* recv a audio message. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvAMessage) { MockBufferIO bio; @@ -736,6 +769,9 @@ VOID TEST(ProtocolStackTest, ProtocolRecvAMessage) EXPECT_TRUE(msg->header.is_audio()); } +/** +* recv a video message in 2 chunk packets. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVMessage2Trunk) { MockBufferIO bio; @@ -779,6 +815,9 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVMessage2Trunk) EXPECT_TRUE(msg->header.is_video()); } +/** +* recv video and audio, interlaced in chunks. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAMessage) { MockBufferIO bio; @@ -874,6 +913,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAMessage) } } +/** +* recv video and audio, interlaced in chunks. +* the continue chunks use fmt=1 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAFmt1) { MockBufferIO bio; @@ -988,6 +1031,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAFmt1) } } +/** +* recv video and audio, interlaced in chunks. +* the continue chunks use fmt=2 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAFmt2) { MockBufferIO bio; @@ -1100,6 +1147,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAFmt2) } } +/** +* recv video and audio, interlaced in chunks. +* the continue chunks use fmt=3 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAFmt3) { MockBufferIO bio; @@ -1211,6 +1262,9 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAFmt3) } } +/** +* recv video, audio and video, interlaced in chunks. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVMessage) { MockBufferIO bio; @@ -1363,6 +1417,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVMessage) } } +/** +* recv video, audio and video, interlaced in chunks. +* the continue chunks use fmt=1 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVFmt1) { MockBufferIO bio; @@ -1527,6 +1585,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVFmt1) } } +/** +* recv video, audio and video, interlaced in chunks. +* the continue chunks use fmt=2 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVFmt2) { MockBufferIO bio; @@ -1689,6 +1751,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVFmt2) } } +/** +* recv video, audio and video, interlaced in chunks. +* the continue chunks use fmt=3 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVFmt3) { MockBufferIO bio; @@ -1850,6 +1916,9 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVFmt3) } } +/** +* recv video, audio, video and video, interlaced in chunks. +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVMessage) { MockBufferIO bio; @@ -2055,6 +2124,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVMessage) } } +/** +* recv video, audio, video and video, interlaced in chunks. +* the continue chunks use fmt=1 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt1) { MockBufferIO bio; @@ -2271,6 +2344,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt1) } } +/** +* recv video, audio, video and video, interlaced in chunks. +* the continue chunks use fmt=2 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt2) { MockBufferIO bio; @@ -2483,6 +2560,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt2) } } +/** +* recv video, audio, video and video, interlaced in chunks. +* the continue chunks use fmt=3 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt3) { MockBufferIO bio; @@ -2693,6 +2774,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt3) } } +/** +* recv video, audio, video and video, interlaced in chunks. +* the continue chunks use fmt=1, last video with fmt=1 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt11) { MockBufferIO bio; @@ -2909,6 +2994,11 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt11) } } +/** +* recv video, audio, video and video, interlaced in chunks. +* the continue chunks use fmt=1, last video with fmt=1 header, +* last video changed length +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt11Length) { MockBufferIO bio; @@ -3126,6 +3216,10 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt11Length) } } +/** +* recv video, audio, video and video, interlaced in chunks. +* the continue chunks use fmt=1, last video with fmt=2 header +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt12) { MockBufferIO bio; @@ -3340,6 +3434,11 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt12) } } +/** +* recv video, audio, video and video, interlaced in chunks. +* the continue chunks use fmt=1, last video with fmt=2 header, +* last video changed length +*/ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt12Length) { MockBufferIO bio; @@ -3559,3 +3658,770 @@ VOID TEST(ProtocolStackTest, ProtocolRecvVAVVFmt12Length) } } +/** +* recv video, with extended timestamp. +* small timestamp < 0xffffff +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvExtTimeMessage) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + /** + * parse the message header. + * 3bytes: timestamp delta, fmt=0,1,2 + * 3bytes: payload length, fmt=0,1 + * 1bytes: message type, fmt=0,1 + * 4bytes: stream id, fmt=0 + * where: + * fmt=0, 0x0X + * fmt=1, 0x4X + * fmt=2, 0x8X + * fmt=3, 0xCX + */ + + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x03, + (char)0xff, (char)0xff, (char)0xff, // timestamp + (char)0x00, (char)0x00, (char)0x04, // length + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + (char)0x00, (char)0x00, (char)0x00, (char)0x10, // extended timestamp + // msg payload start + (char)0x00, (char)0x00, (char)0x07, (char)0x63 + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + EXPECT_EQ(0x10, msg->header.timestamp); +} + +/** +* recv video, with extended timestamp. +* big timestamp > 0xffffff +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvExtTimeMessage2) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + /** + * parse the message header. + * 3bytes: timestamp delta, fmt=0,1,2 + * 3bytes: payload length, fmt=0,1 + * 1bytes: message type, fmt=0,1 + * 4bytes: stream id, fmt=0 + * where: + * fmt=0, 0x0X + * fmt=1, 0x4X + * fmt=2, 0x8X + * fmt=3, 0xCX + */ + + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x03, + (char)0xff, (char)0xff, (char)0xff, // timestamp + (char)0x00, (char)0x00, (char)0x04, // length + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + (char)0x7f, (char)0x01, (char)0x02, (char)0x03, // extended timestamp + // msg payload start + (char)0x00, (char)0x00, (char)0x07, (char)0x63 + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + EXPECT_EQ(0x7f010203, msg->header.timestamp); +} + +/** +* recv video, with extended timestamp. +* always use 31bits timestamp. +*/ +// always use 31bits timestamp, for some server may use 32bits extended timestamp. +// @see https://github.com/winlinvip/simple-rtmp-server/issues/111 +VOID TEST(ProtocolStackTest, ProtocolRecvExtTimeMessage3) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + /** + * parse the message header. + * 3bytes: timestamp delta, fmt=0,1,2 + * 3bytes: payload length, fmt=0,1 + * 1bytes: message type, fmt=0,1 + * 4bytes: stream id, fmt=0 + * where: + * fmt=0, 0x0X + * fmt=1, 0x4X + * fmt=2, 0x8X + * fmt=3, 0xCX + */ + + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x03, + (char)0xff, (char)0xff, (char)0xff, // timestamp + (char)0x00, (char)0x00, (char)0x04, // length + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + (char)0xff, (char)0x01, (char)0x02, (char)0x03, // extended timestamp + // msg payload start + (char)0x00, (char)0x00, (char)0x07, (char)0x63 + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // always use 31bits timestamp + EXPECT_EQ(0x7f010203, msg->header.timestamp); +} + +/** +* recv video, with extended timestamp, in 2 chunks packet. +* always send extended timestamp in 0xCX chunk packets. +*/ +/** +* RTMP specification and ffmpeg/librtmp is false, +* but, adobe changed the specification, so flash/FMLE/FMS always true. +* default to true to support flash/FMLE/FMS. +* +* ffmpeg/librtmp may donot send this filed, need to detect the value. +* @see also: http://blog.csdn.net/win_lin/article/details/13363699 +* compare to the chunk timestamp, which is set by chunk message header +* type 0,1 or 2. +* +* @remark, nginx send the extended-timestamp in sequence-header, +* and timestamp delta in continue C1 chunks, and so compatible with ffmpeg, +* that is, there is no continue chunks and extended-timestamp in nginx-rtmp. +* +* @remark, srs always send the extended-timestamp, to keep simple, +* and compatible with adobe products. +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVExtTime2Trunk) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x03, + (char)0xff, (char)0xff, (char)0xff, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + (char)0x00, (char)0x01, (char)0x02, (char)0x03, // extended timestamp + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC3, + (char)0x00, (char)0x01, (char)0x02, (char)0x03, // extended timestamp + /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC3, + (char)0x00, (char)0x01, (char)0x02, (char)0x03, // extended timestamp + /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 0xCX with extended timestamp. + EXPECT_EQ(0x00010203, msg->header.timestamp); +} + +/** +* recv video, with extended timestamp, in 2 chunks packet. +* never send extended timestamp in 0xCX chunk packets. +*/ +// FFMPEG/librtmp, RTMP specification standard protocol. +VOID TEST(ProtocolStackTest, ProtocolRecvVExtTime2Trunk2) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x03, + (char)0xff, (char)0xff, (char)0xff, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + (char)0x00, (char)0x01, (char)0x02, (char)0x03, // extended timestamp + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC3, + /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC3, + /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 0xCX without extended timestamp. + EXPECT_EQ(0x00010203, msg->header.timestamp); +} + +/** +* a video message, in 2 chunks packet. +* use 1B chunk header, min chunk id is 2. +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid1BMin) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x02, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC2, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC2, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 1B cid(6bits), min is 2 + EXPECT_EQ(0x02, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 1B chunk header, cid in 2-63 +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid1BNormal) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x09, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC9, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC9, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 1B cid(6bits), cid in 2-63 + EXPECT_EQ(0x09, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 1B chunk header, max chunk id is 63. +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid1BMax) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x3F, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xFF, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xFF, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 1B cid(6bits), max is 63 + EXPECT_EQ(0x3F, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 2B chunk header, min chunk id is 64. +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid2BMin) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x00, (char)0x00, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC0, (char)0x00, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC0, (char)0x00, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 2B cid(8bits), min is 64 + EXPECT_EQ(64, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 2B chunk header, cid in 64-319 +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid2BNormal) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x00, (char)0x10, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC0, (char)0x10, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC0, (char)0x10, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 2B cid(8bits), cid in 64-319 + EXPECT_EQ(0x10+64, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 2B chunk header, max chunk id is 319. +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid2BMax) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x00, (char)0xFF, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC0, (char)0xFF, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC0, (char)0xFF, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 2B cid(68bits), max is 319 + EXPECT_EQ(319, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 3B chunk header, min chunk id is 64. +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid3BMin) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x01, (char)0x00, (char)0x00, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC1, (char)0x00, (char)0x00, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC1, (char)0x00, (char)0x00, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 3B cid(16bits), min is 64 + EXPECT_EQ(64, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 3B chunk header, cid in 64-65599 +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid3BNormal) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x01, (char)0x00, (char)0x10, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC1, (char)0x00, (char)0x10, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC1, (char)0x00, (char)0x10, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 3B cid(16bits), cid in 64-65599 + EXPECT_EQ(0x10*256+64, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 3B chunk header, cid in 64-65599, greater than 319 +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid3BNormal2) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x01, (char)0x01, (char)0x10, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC1, (char)0x01, (char)0x10, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC1, (char)0x01, (char)0x10, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 3B cid(16bits), cid in 64-65599 + EXPECT_EQ(0x01 + (0x10*256) + 64, msg->header.perfer_cid); +} + +/** +* a video message, in 2 chunks packet. +* use 3B chunk header, max chunk id is 65599. +*/ +VOID TEST(ProtocolStackTest, ProtocolRecvVCid3BMax) +{ + MockBufferIO bio; + SrsProtocol proto(&bio); + + // video message + char data[] = { + // 12bytes header, 1byts chunk header, 11bytes msg heder + (char)0x01, (char)0xFF, (char)0xFF, + (char)0x00, (char)0x00, (char)0x00, // timestamp + (char)0x00, (char)0x01, (char)0x10, // length, 272 + (char)0x09, // message_type + (char)0x00, (char)0x00, (char)0x00, (char)0x00, // stream_id + // msg payload start + (char)0x02, (char)0x00, (char)0x07, (char)0x63, + (char)0x6f, (char)0x6e, (char)0x6e, (char)0x65, (char)0x63, (char)0x74, (char)0x00, (char)0x3f, (char)0xf0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x03, + (char)0x00, (char)0x03, (char)0x61, (char)0x70, (char)0x70, (char)0x02, (char)0x00, (char)0x04, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, (char)0x00, (char)0x08, (char)0x66, (char)0x6c, + (char)0x61, (char)0x73, (char)0x68, (char)0x56, (char)0x65, (char)0x72, (char)0x02, (char)0x00, (char)0x0d, (char)0x57, (char)0x49, (char)0x4e, (char)0x20, (char)0x31, (char)0x32, (char)0x2c, + (char)0x30, (char)0x2c, (char)0x30, (char)0x2c, (char)0x34, (char)0x31, (char)0x00, (char)0x06, (char)0x73, (char)0x77, (char)0x66, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, + (char)0x51, (char)0x68, (char)0x74, (char)0x74, (char)0x70, (char)0x3a, (char)0x2f, (char)0x2f, (char)0x77, (char)0x77, (char)0x77, (char)0x2e, (char)0x6f, (char)0x73, (char)0x73, (char)0x72, + (char)0x73, (char)0x2e, (char)0x6e, (char)0x65, (char)0x74, (char)0x3a, (char)0x38, (char)0x30, (char)0x38, (char)0x35, (char)0x2f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, + (char)0x72, (char)0x73, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, (char)0x61, (char)0x79, (char)0x65, (char)0x72, (char)0x2f, (char)0x72, (char)0x65, + (char)0x6c, (char)0x65, (char)0x61, (char)0x73, (char)0x65, (char)0x2f, (char)0x73, (char)0x72, (char)0x73, (char)0x5f, (char)0x70, (char)0x6c, + // chunk #2 + (char)0xC1, (char)0xFF, (char)0xFF, /*next chunk.*/ (char)0x61, (char)0x79, (char)0x65, (char)0x72, + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e, + (char)0x32, (char)0x33, (char)0x00, (char)0x05, (char)0x74, (char)0x63, (char)0x55, (char)0x72, (char)0x6c, (char)0x02, (char)0x00, (char)0x14, (char)0x72, (char)0x74, (char)0x6d, (char)0x70, + (char)0x3a, (char)0x2f, (char)0x2f, (char)0x64, (char)0x65, (char)0x76, (char)0x3a, (char)0x31, (char)0x39, (char)0x33, (char)0x35, (char)0x2f, (char)0x6c, (char)0x69, (char)0x76, (char)0x65, + (char)0x00, (char)0x04, (char)0x66, (char)0x70, (char)0x61, (char)0x64, (char)0x01, (char)0x00, (char)0x00, (char)0x0c, (char)0x63, (char)0x61, (char)0x70, (char)0x61, (char)0x62, (char)0x69, + (char)0x6c, (char)0x69, (char)0x74, (char)0x69, (char)0x65, (char)0x73, (char)0x00, (char)0x40, (char)0x6d, (char)0xe0, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + (char)0x0b, (char)0x61, (char)0x75, (char)0x64, (char)0x69, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0xab, (char)0xee, + (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x0b, (char)0x76, (char)0x69, (char)0x64, (char)0x65, (char)0x6f, (char)0x43, (char)0x6f, (char)0x64, (char)0x65, + (char)0x63, (char)0x73, (char)0x00, (char)0x40, (char)0x6f, (char)0x80, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, + // chunk #2 + (char)0xC1, (char)0xFF, (char)0xFF, /*next chunk.*/ + (char)0x2e, (char)0x73, (char)0x77, (char)0x66, (char)0x3f, (char)0x5f, (char)0x76, (char)0x65, (char)0x72, (char)0x73, (char)0x69, (char)0x6f, (char)0x6e, (char)0x3d, (char)0x31, (char)0x2e + }; + bio.in_buffer.append(data, sizeof(data)); + + SrsMessage* msg = NULL; + ASSERT_TRUE(ERROR_SUCCESS == proto.recv_message(&msg)); + SrsAutoFree(SrsMessage, msg); + EXPECT_TRUE(msg->header.is_video()); + // 2B cid(16bits), max is 65599 + EXPECT_EQ(65599, msg->header.perfer_cid); +} +