diff --git a/README.md b/README.md
index 0481ca09e..1a01609a3 100755
--- a/README.md
+++ b/README.md
@@ -220,6 +220,7 @@ Supported operating systems and hardware:
* 2013-10-17, Created.
## History
+* v2.0, 2014-10-25, fix [#185](https://github.com/winlinvip/simple-rtmp-server/issues/185), AMF0 support 0x0B the date type codec. 2.0.5.
* v2.0, 2014-10-24, fix [#186](https://github.com/winlinvip/simple-rtmp-server/issues/186), hotfix for bug #186, drop connect args when not object. 2.0.4.
* v2.0, 2014-10-24, rename wiki/xxx to wiki/v1_CN_xxx. 2.0.3.
* v2.0, 2014-10-19, fix [#184](https://github.com/winlinvip/simple-rtmp-server/issues/184), support AnnexB in RTMP body for HLS. 2.0.2
diff --git a/trunk/research/players/srs_player/release/srs_player.swf b/trunk/research/players/srs_player/release/srs_player.swf
index dff28fe19..82aca05c3 100755
Binary files a/trunk/research/players/srs_player/release/srs_player.swf and b/trunk/research/players/srs_player/release/srs_player.swf differ
diff --git a/trunk/research/players/srs_player/src/srs_player.as b/trunk/research/players/srs_player/src/srs_player.as
index a8fa5ec2c..5cf1a3c53 100755
--- a/trunk/research/players/srs_player/src/srs_player.as
+++ b/trunk/research/players/srs_player/src/srs_player.as
@@ -377,7 +377,7 @@ package
this.media_conn.connect(null);
} else {
var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/"));
- this.media_conn.connect(tcUrl);
+ this.media_conn.connect(tcUrl, new Date());
}
}
diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp
index c6f6ae378..25b19cb04 100644
--- a/trunk/src/core/srs_core.hpp
+++ b/trunk/src/core/srs_core.hpp
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR "2"
#define VERSION_MINOR "0"
-#define VERSION_REVISION "6"
+#define VERSION_REVISION "7"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info.
#define RTMP_SIG_SRS_KEY "SRS"
diff --git a/trunk/src/rtmp/srs_protocol_amf0.cpp b/trunk/src/rtmp/srs_protocol_amf0.cpp
index 91df82614..2b6fdb95b 100644
--- a/trunk/src/rtmp/srs_protocol_amf0.cpp
+++ b/trunk/src/rtmp/srs_protocol_amf0.cpp
@@ -109,6 +109,11 @@ bool SrsAmf0Any::is_strict_array()
return marker == RTMP_AMF0_StrictArray;
}
+bool SrsAmf0Any::is_date()
+{
+ return marker == RTMP_AMF0_Date;
+}
+
bool SrsAmf0Any::is_complex_object()
{
return is_object() || is_object_eof() || is_ecma_array() || is_strict_array();
@@ -142,6 +147,20 @@ double SrsAmf0Any::to_number()
return p->value;
}
+int64_t SrsAmf0Any::to_date()
+{
+ SrsAmf0Date* p = dynamic_cast(this);
+ srs_assert(p != NULL);
+ return p->date();
+}
+
+int16_t SrsAmf0Any::to_date_time_zone()
+{
+ SrsAmf0Date* p = dynamic_cast(this);
+ srs_assert(p != NULL);
+ return p->time_zone();
+}
+
SrsAmf0Object* SrsAmf0Any::to_object()
{
SrsAmf0Object* p = dynamic_cast(this);
@@ -189,6 +208,9 @@ void __srs_amf0_do_print(SrsAmf0Any* any, stringstream& ss, int level)
ss << "Number " << std::fixed << any->to_number() << endl;
} else if (any->is_string()) {
ss << "String " << any->to_str() << endl;
+ } else if (any->is_date()) {
+ ss << "Date " << std::hex << any->to_date()
+ << "/" << std::hex << any->to_date_time_zone() << endl;
} else if (any->is_null()) {
ss << "Null" << endl;
} else if (any->is_ecma_array()) {
@@ -304,6 +326,11 @@ SrsAmf0StrictArray* SrsAmf0Any::strict_array()
return new SrsAmf0StrictArray();
}
+SrsAmf0Any* SrsAmf0Any::date(int64_t value)
+{
+ return new SrsAmf0Date(value);
+}
+
int SrsAmf0Any::discovery(SrsStream* stream, SrsAmf0Any** ppvalue)
{
int ret = ERROR_SUCCESS;
@@ -360,6 +387,10 @@ int SrsAmf0Any::discovery(SrsStream* stream, SrsAmf0Any** ppvalue)
*ppvalue = SrsAmf0Any::strict_array();
return ret;
}
+ case RTMP_AMF0_Date: {
+ *ppvalue = SrsAmf0Any::date();
+ return ret;
+ }
case RTMP_AMF0_Invalid:
default: {
ret = ERROR_RTMP_AMF0_INVALID;
@@ -805,7 +836,7 @@ int SrsAmf0EcmaArray::read(SrsStream* stream)
if (marker != RTMP_AMF0_EcmaArray) {
ret = ERROR_RTMP_AMF0_DECODE;
srs_error("amf0 check ecma_array marker failed. "
- "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret);
+ "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_EcmaArray, ret);
return ret;
}
srs_verbose("amf0 read ecma_array marker success");
@@ -1003,7 +1034,7 @@ int SrsAmf0StrictArray::read(SrsStream* stream)
if (marker != RTMP_AMF0_StrictArray) {
ret = ERROR_RTMP_AMF0_DECODE;
srs_error("amf0 check strict_array marker failed. "
- "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret);
+ "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_StrictArray, ret);
return ret;
}
srs_verbose("amf0 read strict_array marker success");
@@ -1127,6 +1158,11 @@ int SrsAmf0Size::number()
return 1 + 8;
}
+int SrsAmf0Size::date()
+{
+ return 1 + 8 + 2;
+}
+
int SrsAmf0Size::null()
{
return 1;
@@ -1278,6 +1314,130 @@ SrsAmf0Any* SrsAmf0Number::copy()
return copy;
}
+SrsAmf0Date::SrsAmf0Date(int64_t value)
+{
+ marker = RTMP_AMF0_Date;
+ _date_value = value;
+ _time_zone = 0;
+}
+
+SrsAmf0Date::~SrsAmf0Date()
+{
+}
+
+int SrsAmf0Date::total_size()
+{
+ return SrsAmf0Size::date();
+}
+
+int SrsAmf0Date::read(SrsStream* stream)
+{
+ int ret = ERROR_SUCCESS;
+
+ // marker
+ if (!stream->require(1)) {
+ ret = ERROR_RTMP_AMF0_DECODE;
+ srs_error("amf0 read date marker failed. ret=%d", ret);
+ return ret;
+ }
+
+ char marker = stream->read_1bytes();
+ if (marker != RTMP_AMF0_Date) {
+ ret = ERROR_RTMP_AMF0_DECODE;
+ srs_error("amf0 check date marker failed. "
+ "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Date, ret);
+ return ret;
+ }
+ srs_verbose("amf0 read date marker success");
+
+ // date value
+ // An ActionScript Date is serialized as the number of milliseconds
+ // elapsed since the epoch of midnight on 1st Jan 1970 in the UTC
+ // time zone.
+ if (!stream->require(8)) {
+ ret = ERROR_RTMP_AMF0_DECODE;
+ srs_error("amf0 read date failed. ret=%d", ret);
+ return ret;
+ }
+
+ _date_value = stream->read_8bytes();
+ srs_verbose("amf0 read date success. date=%"PRId64, _date_value);
+
+ // time zone
+ // While the design of this type reserves room for time zone offset
+ // information, it should not be filled in, nor used, as it is unconventional
+ // to change time zones when serializing dates on a network. It is suggested
+ // that the time zone be queried independently as needed.
+ if (!stream->require(2)) {
+ ret = ERROR_RTMP_AMF0_DECODE;
+ srs_error("amf0 read time zone failed. ret=%d", ret);
+ return ret;
+ }
+
+ _time_zone = stream->read_2bytes();
+ srs_verbose("amf0 read time zone success. zone=%d", _time_zone);
+
+ return ret;
+}
+int SrsAmf0Date::write(SrsStream* stream)
+{
+ int ret = ERROR_SUCCESS;
+
+ // marker
+ if (!stream->require(1)) {
+ ret = ERROR_RTMP_AMF0_ENCODE;
+ srs_error("amf0 write date marker failed. ret=%d", ret);
+ return ret;
+ }
+
+ stream->write_1bytes(RTMP_AMF0_Date);
+ srs_verbose("amf0 write date marker success");
+
+ // date value
+ if (!stream->require(8)) {
+ ret = ERROR_RTMP_AMF0_ENCODE;
+ srs_error("amf0 write date failed. ret=%d", ret);
+ return ret;
+ }
+
+ stream->write_8bytes(_date_value);
+ srs_verbose("amf0 write date success. date=%"PRId64, _date_value);
+
+ // time zone
+ if (!stream->require(2)) {
+ ret = ERROR_RTMP_AMF0_ENCODE;
+ srs_error("amf0 write time zone failed. ret=%d", ret);
+ return ret;
+ }
+
+ stream->write_2bytes(_time_zone);
+ srs_verbose("amf0 write time zone success. date=%d", _time_zone);
+
+ srs_verbose("write date object success.");
+
+ return ret;
+}
+
+SrsAmf0Any* SrsAmf0Date::copy()
+{
+ SrsAmf0Date* copy = new SrsAmf0Date(0);
+
+ copy->_date_value = _date_value;
+ copy->_time_zone = _time_zone;
+
+ return copy;
+}
+
+int64_t SrsAmf0Date::date()
+{
+ return _date_value;
+}
+
+int16_t SrsAmf0Date::time_zone()
+{
+ return _time_zone;
+}
+
SrsAmf0Null::SrsAmf0Null()
{
marker = RTMP_AMF0_Null;
diff --git a/trunk/src/rtmp/srs_protocol_amf0.hpp b/trunk/src/rtmp/srs_protocol_amf0.hpp
index 1ecc3f4ae..bbf27459a 100644
--- a/trunk/src/rtmp/srs_protocol_amf0.hpp
+++ b/trunk/src/rtmp/srs_protocol_amf0.hpp
@@ -43,6 +43,7 @@ namespace _srs_internal
{
class SrsUnSortedHashtable;
class SrsAmf0ObjectEOF;
+ class SrsAmf0Date;
}
/*
@@ -185,6 +186,12 @@ public:
*/
virtual bool is_strict_array();
/**
+ * whether current instance is an AMF0 date.
+ * @return true if instance is an AMF0 date; otherwise, false.
+ * @remark, if true, use to_date() to get its value.
+ */
+ virtual bool is_date();
+ /**
* whether current instance is an AMF0 object, object-EOF, ecma-array or strict-array.
*/
virtual bool is_complex_object();
@@ -212,6 +219,12 @@ public:
*/
virtual double to_number();
/**
+ * convert instance to date,
+ * @remark assert is_date(), user must ensure the type then convert.
+ */
+ virtual int64_t to_date();
+ virtual int16_t to_date_time_zone();
+ /**
* convert instance to amf0 object,
* @remark assert is_object(), user must ensure the type then convert.
*/
@@ -274,6 +287,10 @@ public:
*/
static SrsAmf0Any* number(double value = 0.0);
/**
+ * create an AMF0 date instance
+ */
+ static SrsAmf0Any* date(int64_t value = 0);
+ /**
* create an AMF0 null instance
*/
static SrsAmf0Any* null();
@@ -532,6 +549,7 @@ public:
static int utf8(std::string value);
static int str(std::string value);
static int number();
+ static int date();
static int null();
static int undefined();
static int boolean();
@@ -673,6 +691,43 @@ namespace _srs_internal
virtual SrsAmf0Any* copy();
};
+ /**
+ * 2.13 Date Type
+ * time-zone = S16 ; reserved, not supported should be set to 0x0000
+ * date-type = date-marker DOUBLE time-zone
+ * @see: https://github.com/winlinvip/simple-rtmp-server/issues/185
+ */
+ class SrsAmf0Date : public SrsAmf0Any
+ {
+ private:
+ int64_t _date_value;
+ int16_t _time_zone;
+ private:
+ friend class SrsAmf0Any;
+ /**
+ * make amf0 date to private,
+ * use should never declare it, use SrsAmf0Any::date() to create it.
+ */
+ SrsAmf0Date(int64_t value);
+ public:
+ virtual ~SrsAmf0Date();
+ // serialize/deserialize to/from stream.
+ public:
+ virtual int total_size();
+ virtual int read(SrsStream* stream);
+ virtual int write(SrsStream* stream);
+ virtual SrsAmf0Any* copy();
+ public:
+ /**
+ * get the date value.
+ */
+ virtual int64_t date();
+ /**
+ * get the time_zone.
+ */
+ virtual int16_t time_zone();
+ };
+
/**
* read amf0 null from stream.
* 2.7 null Type