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