diff --git a/README.md b/README.md
index 76341197e..7bd45e439 100755
--- a/README.md
+++ b/README.md
@@ -154,6 +154,8 @@ Please select according to languages:
### V3 changes
+* v3.0, 2019-10-30, Cover protocol stack RTMP. 3.0.63
+* v3.0, 2019-10-23, Cover JSON codec. 3.0.62
* v3.0, 2019-10-13, Use http://ossrs.net:8000 as homepage.
* v3.0, 2019-10-10, Cover AMF0 codec. 3.0.61
* v3.0, 2019-10-07, [3.0 alpha1(3.0.60)][r3.0a1] released. 107962 lines.
diff --git a/trunk/configure b/trunk/configure
index e4f75de9b..d5e6b3082 100755
--- a/trunk/configure
+++ b/trunk/configure
@@ -314,9 +314,8 @@ fi
#
# utest, the unit-test cases of srs, base on gtest1.6
if [ $SRS_UTEST = YES ]; then
- MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol"
- "srs_utest_kernel" "srs_utest_core" "srs_utest_config"
- "srs_utest_reload" "srs_utest_service" "srs_utest_app")
+ MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core"
+ "srs_utest_config" "srs_utest_protostack" "srs_utest_reload" "srs_utest_service" "srs_utest_app")
ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot})
ModuleLibFiles=(${LibSTfile} ${LibSSLfile})
MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP")
diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp
index 5a8617454..8f4e8f406 100644
--- a/trunk/src/core/srs_core.hpp
+++ b/trunk/src/core/srs_core.hpp
@@ -27,7 +27,7 @@
// The version config.
#define VERSION_MAJOR 3
#define VERSION_MINOR 0
-#define VERSION_REVISION 62
+#define VERSION_REVISION 63
// The macros generated by configure script.
#include
diff --git a/trunk/src/protocol/srs_protocol_json.cpp b/trunk/src/protocol/srs_protocol_json.cpp
index a87159fdb..f7bd1c5ed 100644
--- a/trunk/src/protocol/srs_protocol_json.cpp
+++ b/trunk/src/protocol/srs_protocol_json.cpp
@@ -1632,11 +1632,9 @@ SrsAmf0Any* SrsJsonAny::to_amf0()
srs_assert(false);
}
default: {
- break;
+ return SrsAmf0Any::null();
}
}
-
- return SrsAmf0Any::null();
}
SrsJsonAny* SrsJsonAny::str(const char* value)
@@ -1729,8 +1727,6 @@ SrsJsonAny* srs_json_parse_tree(json_value* node)
default:
return NULL;
}
-
- return NULL;
}
SrsJsonAny* SrsJsonAny::loads(const string& str)
@@ -1974,9 +1970,10 @@ SrsJsonAny* SrsJsonArray::at(int index)
return elem;
}
-void SrsJsonArray::add(SrsJsonAny* value)
+SrsJsonArray* SrsJsonArray::add(SrsJsonAny* value)
{
properties.push_back(value);
+ return this;
}
SrsJsonArray* SrsJsonArray::append(SrsJsonAny* value)
diff --git a/trunk/src/protocol/srs_protocol_json.hpp b/trunk/src/protocol/srs_protocol_json.hpp
index 1eedd9b23..0e3d8cab0 100644
--- a/trunk/src/protocol/srs_protocol_json.hpp
+++ b/trunk/src/protocol/srs_protocol_json.hpp
@@ -156,7 +156,7 @@ public:
virtual int count();
// @remark: max index is count().
virtual SrsJsonAny* at(int index);
- virtual void add(SrsJsonAny* value);
+ virtual SrsJsonArray* add(SrsJsonAny* value);
// alias to add.
virtual SrsJsonArray* append(SrsJsonAny* value);
public:
diff --git a/trunk/src/utest/srs_utest_amf0.cpp b/trunk/src/utest/srs_utest_amf0.cpp
index b42823366..0ca210ab5 100644
--- a/trunk/src/utest/srs_utest_amf0.cpp
+++ b/trunk/src/utest/srs_utest_amf0.cpp
@@ -2499,6 +2499,11 @@ VOID TEST(ProtocolJSONTest, Interfaces)
SrsJsonAny* p = SrsJsonAny::str();
EXPECT_TRUE(p->is_string());
EXPECT_TRUE(p->to_str().empty());
+
+ SrsAmf0Any* a = p->to_amf0();
+ EXPECT_TRUE(a->is_string());
+
+ srs_freep(a);
srs_freep(p);
}
@@ -2506,6 +2511,11 @@ VOID TEST(ProtocolJSONTest, Interfaces)
SrsJsonAny* p = SrsJsonAny::str("hello");
EXPECT_TRUE(p->is_string());
EXPECT_TRUE(string("hello") == p->to_str());
+
+ SrsAmf0Any* a = p->to_amf0();
+ EXPECT_TRUE(a->is_string());
+
+ srs_freep(a);
srs_freep(p);
}
@@ -2513,6 +2523,44 @@ VOID TEST(ProtocolJSONTest, Interfaces)
SrsJsonAny* p = SrsJsonAny::str("hello", 2);
EXPECT_TRUE(p->is_string());
EXPECT_TRUE(string("he") == p->to_str());
+
+ SrsAmf0Any* a = p->to_amf0();
+ EXPECT_TRUE(a->is_string());
+
+ srs_freep(a);
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::boolean(true);
+ EXPECT_TRUE(p->is_boolean());
+
+ SrsAmf0Any* a = p->to_amf0();
+ EXPECT_TRUE(a->is_boolean());
+
+ srs_freep(a);
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::integer();
+ EXPECT_TRUE(p->is_integer());
+
+ SrsAmf0Any* a = p->to_amf0();
+ EXPECT_TRUE(a->is_number());
+
+ srs_freep(a);
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::number();
+ EXPECT_TRUE(p->is_number());
+
+ SrsAmf0Any* a = p->to_amf0();
+ EXPECT_TRUE(a->is_number());
+
+ srs_freep(a);
srs_freep(p);
}
}
@@ -2573,5 +2621,170 @@ VOID TEST(ProtocolJSONTest, Dumps)
EXPECT_STREQ("[]", p->dumps().c_str());
srs_freep(p);
}
+
+ if (true) {
+ SrsJsonObject* p = SrsJsonAny::object();
+ p->set("id", SrsJsonAny::integer(3));
+ p->set("year", SrsJsonAny::integer(2019));
+ EXPECT_STREQ("{\"id\":3,\"year\":2019}", p->dumps().c_str());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonArray* p = SrsJsonAny::array();
+ p->add(SrsJsonAny::integer(3));
+ p->add(SrsJsonAny::integer(2));
+ EXPECT_STREQ("[3,2]", p->dumps().c_str());
+ srs_freep(p);
+ }
+}
+
+VOID TEST(ProtocolJSONTest, Parse)
+{
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("\"hello\"");
+ EXPECT_TRUE(p->is_string());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("true");
+ EXPECT_TRUE(p->is_boolean());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("3");
+ EXPECT_TRUE(p->is_integer());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("3.0");
+ EXPECT_TRUE(p->is_number());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("null");
+ EXPECT_TRUE(p->is_null());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("{}");
+ EXPECT_TRUE(p->is_object());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("[]");
+ EXPECT_TRUE(p->is_array());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("{\"id\":3}");
+ EXPECT_TRUE(p->is_object());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("[\"id\",3]");
+ EXPECT_TRUE(p->is_array());
+ srs_freep(p);
+ }
+}
+
+VOID TEST(ProtocolJSONTest, ObjectAPI)
+{
+ SrsJsonObject* p = SrsJsonAny::object();
+ SrsAutoFree(SrsJsonObject, p);
+
+ p->set("id", SrsJsonAny::integer(3));
+ p->set("name", SrsJsonAny::str("srs"));
+
+ EXPECT_STREQ("name", p->key_at(1).c_str());
+ EXPECT_STREQ("srs", p->value_at(1)->to_str().c_str());
+
+ p->set("name", NULL);
+ p->set("name", SrsJsonAny::str("ossrs"));
+ p->set("version", SrsJsonAny::number(3.1));
+ p->set("stable", SrsJsonAny::boolean(true));
+
+ SrsJsonObject* pp = SrsJsonAny::object();
+ p->set("args", pp);
+ pp->set("url", SrsJsonAny::str("ossrs.net"));
+ pp->set("year", SrsJsonAny::integer(2019));
+
+ SrsJsonArray* pa = SrsJsonAny::array();
+ p->set("authors", pa);
+ pa->add(SrsJsonAny::str("winlin"));
+ pa->add(SrsJsonAny::str("wenjie"));
+
+ SrsJsonAny* prop = p->get_property("name");
+ EXPECT_STREQ("ossrs", prop->to_str().c_str());
+ EXPECT_STREQ("ossrs", p->ensure_property_string("name")->to_str().c_str());
+
+ EXPECT_TRUE(NULL == p->get_property("invalid"));
+ EXPECT_TRUE(NULL == p->ensure_property_string("invalid"));
+ EXPECT_TRUE(NULL == p->ensure_property_string("id"));
+
+ EXPECT_TRUE(NULL == p->ensure_property_integer("invalid"));
+ EXPECT_TRUE(NULL == p->ensure_property_integer("name"));
+ EXPECT_EQ(3, p->ensure_property_integer("id")->to_integer());
+
+ EXPECT_TRUE(NULL == p->ensure_property_number("invalid"));
+ EXPECT_TRUE(NULL == p->ensure_property_number("name"));
+ EXPECT_EQ(3.1, p->ensure_property_number("version")->to_number());
+
+ EXPECT_TRUE(NULL == p->ensure_property_boolean("invalid"));
+ EXPECT_TRUE(NULL == p->ensure_property_boolean("name"));
+ EXPECT_TRUE(p->ensure_property_boolean("stable")->to_boolean());
+
+ EXPECT_TRUE(NULL == p->ensure_property_object("invalid"));
+ EXPECT_TRUE(NULL == p->ensure_property_object("name"));
+ EXPECT_TRUE(NULL != p->ensure_property_object("args")->to_object());
+
+ EXPECT_TRUE(NULL == p->ensure_property_array("invalid"));
+ EXPECT_TRUE(NULL == p->ensure_property_array("name"));
+ EXPECT_TRUE(NULL != p->ensure_property_array("authors")->to_array());
+
+ SrsAmf0Object* a = (SrsAmf0Object*)p->to_amf0();
+ EXPECT_EQ(6, a->count());
+ srs_freep(a);
+}
+
+VOID TEST(ProtocolJSONTest, ArrayAPI)
+{
+ SrsJsonArray* p = SrsJsonAny::array();
+ SrsAutoFree(SrsJsonArray, p);
+
+ p->add(SrsJsonAny::integer(2019));
+ p->add(SrsJsonAny::str("srs"));
+ p->add(SrsJsonAny::boolean(true));
+
+ EXPECT_STREQ("srs", p->at(1)->to_str().c_str());
+
+ SrsAmf0StrictArray* a = (SrsAmf0StrictArray*)p->to_amf0();
+ EXPECT_EQ(3, a->count());
+ srs_freep(a);
+}
+
+VOID TEST(ProtocolJSONTest, ParseSpecial)
+{
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("[\"hello\"\r\n, 2019]");
+ EXPECT_TRUE(p->is_array());
+ EXPECT_EQ(2, p->to_array()->count());
+ srs_freep(p);
+ }
+
+ if (true) {
+ SrsJsonAny* p = SrsJsonAny::loads("[\"hello\"\r\n, 2019, \"\\xe6\\xb5\\x81\"]");
+ EXPECT_TRUE(p->is_array());
+ EXPECT_EQ(3, p->to_array()->count());
+ srs_freep(p);
+ }
}
diff --git a/trunk/src/utest/srs_utest_protostack.cpp b/trunk/src/utest/srs_utest_protostack.cpp
new file mode 100644
index 000000000..3c26e3452
--- /dev/null
+++ b/trunk/src/utest/srs_utest_protostack.cpp
@@ -0,0 +1,151 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2013-2019 Winlin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+class MockErrorPacket : public SrsPacket
+{
+protected:
+ virtual int get_size() {
+ return 1024;
+ }
+};
+
+VOID TEST(ProtoStackTest, PacketEncode)
+{
+ srs_error_t err;
+
+ int size;
+ char* payload;
+
+ if (true) {
+ MockErrorPacket pkt;
+ HELPER_EXPECT_FAILED(pkt.encode(size, payload));
+ }
+
+ if (true) {
+ MockErrorPacket pkt;
+ SrsBuffer b;
+ HELPER_EXPECT_FAILED(pkt.decode(&b));
+ }
+
+ if (true) {
+ SrsPacket pkt;
+ EXPECT_EQ(0, pkt.get_prefer_cid());
+ EXPECT_EQ(0, pkt.get_message_type());
+ EXPECT_EQ(0, pkt.get_size());
+ }
+
+ if (true) {
+ MockErrorPacket pkt;
+ EXPECT_EQ(1024, pkt.get_size());
+ }
+}
+
+VOID TEST(ProtoStackTest, ManualFlush)
+{
+ srs_error_t err;
+
+ if (true) {
+ MockBufferIO io;
+ SrsProtocol p(&io);
+
+ // Always response ACK message.
+ HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1));
+
+ // Default is auto response.
+ HELPER_EXPECT_SUCCESS(p.response_acknowledgement_message());
+ EXPECT_EQ(12+4, io.out_buffer.length());
+ }
+
+ if (true) {
+ MockBufferIO io;
+ SrsProtocol p(&io);
+
+ // Always response ACK message.
+ HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1));
+
+ p.set_auto_response(true);
+ HELPER_EXPECT_SUCCESS(p.response_acknowledgement_message());
+ EXPECT_EQ(12+4, io.out_buffer.length());
+ }
+
+ if (true) {
+ MockBufferIO io;
+ SrsProtocol p(&io);
+
+ // Always response ACK message.
+ HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1));
+
+ // When not auto response, need to flush it manually.
+ p.set_auto_response(false);
+ HELPER_EXPECT_SUCCESS(p.response_acknowledgement_message());
+ EXPECT_EQ(0, io.out_buffer.length());
+
+ HELPER_EXPECT_SUCCESS(p.manual_response_flush());
+ EXPECT_EQ(12+4, io.out_buffer.length());
+ }
+
+ if (true) {
+ MockBufferIO io;
+ SrsProtocol p(&io);
+
+ // Always response ACK message.
+ HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1));
+
+ HELPER_EXPECT_SUCCESS(p.response_ping_message(1024));
+ EXPECT_EQ(12+6, io.out_buffer.length());
+ }
+
+ if (true) {
+ MockBufferIO io;
+ SrsProtocol p(&io);
+
+ // Always response ACK message.
+ HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1));
+
+ // When not auto response, need to flush it manually.
+ p.set_auto_response(false);
+ HELPER_EXPECT_SUCCESS(p.response_ping_message(1024));
+ EXPECT_EQ(0, io.out_buffer.length());
+
+ HELPER_EXPECT_SUCCESS(p.manual_response_flush());
+ EXPECT_EQ(12+6, io.out_buffer.length());
+ }
+}
+
diff --git a/trunk/src/utest/srs_utest_protostack.hpp b/trunk/src/utest/srs_utest_protostack.hpp
new file mode 100644
index 000000000..9f222d46a
--- /dev/null
+++ b/trunk/src/utest/srs_utest_protostack.hpp
@@ -0,0 +1,45 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2013-2019 Winlin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef SRS_UTEST_PROTO_STACK_HPP
+#define SRS_UTEST_PROTO_STACK_HPP
+
+/*
+#include
+*/
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+using namespace _srs_internal;
+
+#include
+
+#endif
+