winlin

fix #185, AMF0 support 0x0B the date type codec. 2.0.5.

@@ -220,6 +220,7 @@ Supported operating systems and hardware: @@ -220,6 +220,7 @@ Supported operating systems and hardware:
220 * 2013-10-17, Created.<br/> 220 * 2013-10-17, Created.<br/>
221 221
222 ## History 222 ## History
  223 +* 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.
223 * 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. 224 * 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.
224 * v2.0, 2014-10-24, rename wiki/xxx to wiki/v1_CN_xxx. 2.0.3. 225 * v2.0, 2014-10-24, rename wiki/xxx to wiki/v1_CN_xxx. 2.0.3.
225 * 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 226 * 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
@@ -377,7 +377,7 @@ package @@ -377,7 +377,7 @@ package
377 this.media_conn.connect(null); 377 this.media_conn.connect(null);
378 } else { 378 } else {
379 var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/")); 379 var tcUrl:String = this.user_url.substr(0, this.user_url.lastIndexOf("/"));
380 - this.media_conn.connect(tcUrl); 380 + this.media_conn.connect(tcUrl, new Date());
381 } 381 }
382 } 382 }
383 383
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "2" 32 #define VERSION_MAJOR "2"
33 #define VERSION_MINOR "0" 33 #define VERSION_MINOR "0"
34 -#define VERSION_REVISION "6" 34 +#define VERSION_REVISION "7"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"
@@ -109,6 +109,11 @@ bool SrsAmf0Any::is_strict_array() @@ -109,6 +109,11 @@ bool SrsAmf0Any::is_strict_array()
109 return marker == RTMP_AMF0_StrictArray; 109 return marker == RTMP_AMF0_StrictArray;
110 } 110 }
111 111
  112 +bool SrsAmf0Any::is_date()
  113 +{
  114 + return marker == RTMP_AMF0_Date;
  115 +}
  116 +
112 bool SrsAmf0Any::is_complex_object() 117 bool SrsAmf0Any::is_complex_object()
113 { 118 {
114 return is_object() || is_object_eof() || is_ecma_array() || is_strict_array(); 119 return is_object() || is_object_eof() || is_ecma_array() || is_strict_array();
@@ -142,6 +147,20 @@ double SrsAmf0Any::to_number() @@ -142,6 +147,20 @@ double SrsAmf0Any::to_number()
142 return p->value; 147 return p->value;
143 } 148 }
144 149
  150 +int64_t SrsAmf0Any::to_date()
  151 +{
  152 + SrsAmf0Date* p = dynamic_cast<SrsAmf0Date*>(this);
  153 + srs_assert(p != NULL);
  154 + return p->date();
  155 +}
  156 +
  157 +int16_t SrsAmf0Any::to_date_time_zone()
  158 +{
  159 + SrsAmf0Date* p = dynamic_cast<SrsAmf0Date*>(this);
  160 + srs_assert(p != NULL);
  161 + return p->time_zone();
  162 +}
  163 +
145 SrsAmf0Object* SrsAmf0Any::to_object() 164 SrsAmf0Object* SrsAmf0Any::to_object()
146 { 165 {
147 SrsAmf0Object* p = dynamic_cast<SrsAmf0Object*>(this); 166 SrsAmf0Object* p = dynamic_cast<SrsAmf0Object*>(this);
@@ -189,6 +208,9 @@ void __srs_amf0_do_print(SrsAmf0Any* any, stringstream& ss, int level) @@ -189,6 +208,9 @@ void __srs_amf0_do_print(SrsAmf0Any* any, stringstream& ss, int level)
189 ss << "Number " << std::fixed << any->to_number() << endl; 208 ss << "Number " << std::fixed << any->to_number() << endl;
190 } else if (any->is_string()) { 209 } else if (any->is_string()) {
191 ss << "String " << any->to_str() << endl; 210 ss << "String " << any->to_str() << endl;
  211 + } else if (any->is_date()) {
  212 + ss << "Date " << std::hex << any->to_date()
  213 + << "/" << std::hex << any->to_date_time_zone() << endl;
192 } else if (any->is_null()) { 214 } else if (any->is_null()) {
193 ss << "Null" << endl; 215 ss << "Null" << endl;
194 } else if (any->is_ecma_array()) { 216 } else if (any->is_ecma_array()) {
@@ -304,6 +326,11 @@ SrsAmf0StrictArray* SrsAmf0Any::strict_array() @@ -304,6 +326,11 @@ SrsAmf0StrictArray* SrsAmf0Any::strict_array()
304 return new SrsAmf0StrictArray(); 326 return new SrsAmf0StrictArray();
305 } 327 }
306 328
  329 +SrsAmf0Any* SrsAmf0Any::date(int64_t value)
  330 +{
  331 + return new SrsAmf0Date(value);
  332 +}
  333 +
307 int SrsAmf0Any::discovery(SrsStream* stream, SrsAmf0Any** ppvalue) 334 int SrsAmf0Any::discovery(SrsStream* stream, SrsAmf0Any** ppvalue)
308 { 335 {
309 int ret = ERROR_SUCCESS; 336 int ret = ERROR_SUCCESS;
@@ -360,6 +387,10 @@ int SrsAmf0Any::discovery(SrsStream* stream, SrsAmf0Any** ppvalue) @@ -360,6 +387,10 @@ int SrsAmf0Any::discovery(SrsStream* stream, SrsAmf0Any** ppvalue)
360 *ppvalue = SrsAmf0Any::strict_array(); 387 *ppvalue = SrsAmf0Any::strict_array();
361 return ret; 388 return ret;
362 } 389 }
  390 + case RTMP_AMF0_Date: {
  391 + *ppvalue = SrsAmf0Any::date();
  392 + return ret;
  393 + }
363 case RTMP_AMF0_Invalid: 394 case RTMP_AMF0_Invalid:
364 default: { 395 default: {
365 ret = ERROR_RTMP_AMF0_INVALID; 396 ret = ERROR_RTMP_AMF0_INVALID;
@@ -805,7 +836,7 @@ int SrsAmf0EcmaArray::read(SrsStream* stream) @@ -805,7 +836,7 @@ int SrsAmf0EcmaArray::read(SrsStream* stream)
805 if (marker != RTMP_AMF0_EcmaArray) { 836 if (marker != RTMP_AMF0_EcmaArray) {
806 ret = ERROR_RTMP_AMF0_DECODE; 837 ret = ERROR_RTMP_AMF0_DECODE;
807 srs_error("amf0 check ecma_array marker failed. " 838 srs_error("amf0 check ecma_array marker failed. "
808 - "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret); 839 + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_EcmaArray, ret);
809 return ret; 840 return ret;
810 } 841 }
811 srs_verbose("amf0 read ecma_array marker success"); 842 srs_verbose("amf0 read ecma_array marker success");
@@ -1003,7 +1034,7 @@ int SrsAmf0StrictArray::read(SrsStream* stream) @@ -1003,7 +1034,7 @@ int SrsAmf0StrictArray::read(SrsStream* stream)
1003 if (marker != RTMP_AMF0_StrictArray) { 1034 if (marker != RTMP_AMF0_StrictArray) {
1004 ret = ERROR_RTMP_AMF0_DECODE; 1035 ret = ERROR_RTMP_AMF0_DECODE;
1005 srs_error("amf0 check strict_array marker failed. " 1036 srs_error("amf0 check strict_array marker failed. "
1006 - "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret); 1037 + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_StrictArray, ret);
1007 return ret; 1038 return ret;
1008 } 1039 }
1009 srs_verbose("amf0 read strict_array marker success"); 1040 srs_verbose("amf0 read strict_array marker success");
@@ -1127,6 +1158,11 @@ int SrsAmf0Size::number() @@ -1127,6 +1158,11 @@ int SrsAmf0Size::number()
1127 return 1 + 8; 1158 return 1 + 8;
1128 } 1159 }
1129 1160
  1161 +int SrsAmf0Size::date()
  1162 +{
  1163 + return 1 + 8 + 2;
  1164 +}
  1165 +
1130 int SrsAmf0Size::null() 1166 int SrsAmf0Size::null()
1131 { 1167 {
1132 return 1; 1168 return 1;
@@ -1278,6 +1314,130 @@ SrsAmf0Any* SrsAmf0Number::copy() @@ -1278,6 +1314,130 @@ SrsAmf0Any* SrsAmf0Number::copy()
1278 return copy; 1314 return copy;
1279 } 1315 }
1280 1316
  1317 +SrsAmf0Date::SrsAmf0Date(int64_t value)
  1318 +{
  1319 + marker = RTMP_AMF0_Date;
  1320 + _date_value = value;
  1321 + _time_zone = 0;
  1322 +}
  1323 +
  1324 +SrsAmf0Date::~SrsAmf0Date()
  1325 +{
  1326 +}
  1327 +
  1328 +int SrsAmf0Date::total_size()
  1329 +{
  1330 + return SrsAmf0Size::date();
  1331 +}
  1332 +
  1333 +int SrsAmf0Date::read(SrsStream* stream)
  1334 +{
  1335 + int ret = ERROR_SUCCESS;
  1336 +
  1337 + // marker
  1338 + if (!stream->require(1)) {
  1339 + ret = ERROR_RTMP_AMF0_DECODE;
  1340 + srs_error("amf0 read date marker failed. ret=%d", ret);
  1341 + return ret;
  1342 + }
  1343 +
  1344 + char marker = stream->read_1bytes();
  1345 + if (marker != RTMP_AMF0_Date) {
  1346 + ret = ERROR_RTMP_AMF0_DECODE;
  1347 + srs_error("amf0 check date marker failed. "
  1348 + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Date, ret);
  1349 + return ret;
  1350 + }
  1351 + srs_verbose("amf0 read date marker success");
  1352 +
  1353 + // date value
  1354 + // An ActionScript Date is serialized as the number of milliseconds
  1355 + // elapsed since the epoch of midnight on 1st Jan 1970 in the UTC
  1356 + // time zone.
  1357 + if (!stream->require(8)) {
  1358 + ret = ERROR_RTMP_AMF0_DECODE;
  1359 + srs_error("amf0 read date failed. ret=%d", ret);
  1360 + return ret;
  1361 + }
  1362 +
  1363 + _date_value = stream->read_8bytes();
  1364 + srs_verbose("amf0 read date success. date=%"PRId64, _date_value);
  1365 +
  1366 + // time zone
  1367 + // While the design of this type reserves room for time zone offset
  1368 + // information, it should not be filled in, nor used, as it is unconventional
  1369 + // to change time zones when serializing dates on a network. It is suggested
  1370 + // that the time zone be queried independently as needed.
  1371 + if (!stream->require(2)) {
  1372 + ret = ERROR_RTMP_AMF0_DECODE;
  1373 + srs_error("amf0 read time zone failed. ret=%d", ret);
  1374 + return ret;
  1375 + }
  1376 +
  1377 + _time_zone = stream->read_2bytes();
  1378 + srs_verbose("amf0 read time zone success. zone=%d", _time_zone);
  1379 +
  1380 + return ret;
  1381 +}
  1382 +int SrsAmf0Date::write(SrsStream* stream)
  1383 +{
  1384 + int ret = ERROR_SUCCESS;
  1385 +
  1386 + // marker
  1387 + if (!stream->require(1)) {
  1388 + ret = ERROR_RTMP_AMF0_ENCODE;
  1389 + srs_error("amf0 write date marker failed. ret=%d", ret);
  1390 + return ret;
  1391 + }
  1392 +
  1393 + stream->write_1bytes(RTMP_AMF0_Date);
  1394 + srs_verbose("amf0 write date marker success");
  1395 +
  1396 + // date value
  1397 + if (!stream->require(8)) {
  1398 + ret = ERROR_RTMP_AMF0_ENCODE;
  1399 + srs_error("amf0 write date failed. ret=%d", ret);
  1400 + return ret;
  1401 + }
  1402 +
  1403 + stream->write_8bytes(_date_value);
  1404 + srs_verbose("amf0 write date success. date=%"PRId64, _date_value);
  1405 +
  1406 + // time zone
  1407 + if (!stream->require(2)) {
  1408 + ret = ERROR_RTMP_AMF0_ENCODE;
  1409 + srs_error("amf0 write time zone failed. ret=%d", ret);
  1410 + return ret;
  1411 + }
  1412 +
  1413 + stream->write_2bytes(_time_zone);
  1414 + srs_verbose("amf0 write time zone success. date=%d", _time_zone);
  1415 +
  1416 + srs_verbose("write date object success.");
  1417 +
  1418 + return ret;
  1419 +}
  1420 +
  1421 +SrsAmf0Any* SrsAmf0Date::copy()
  1422 +{
  1423 + SrsAmf0Date* copy = new SrsAmf0Date(0);
  1424 +
  1425 + copy->_date_value = _date_value;
  1426 + copy->_time_zone = _time_zone;
  1427 +
  1428 + return copy;
  1429 +}
  1430 +
  1431 +int64_t SrsAmf0Date::date()
  1432 +{
  1433 + return _date_value;
  1434 +}
  1435 +
  1436 +int16_t SrsAmf0Date::time_zone()
  1437 +{
  1438 + return _time_zone;
  1439 +}
  1440 +
1281 SrsAmf0Null::SrsAmf0Null() 1441 SrsAmf0Null::SrsAmf0Null()
1282 { 1442 {
1283 marker = RTMP_AMF0_Null; 1443 marker = RTMP_AMF0_Null;
@@ -43,6 +43,7 @@ namespace _srs_internal @@ -43,6 +43,7 @@ namespace _srs_internal
43 { 43 {
44 class SrsUnSortedHashtable; 44 class SrsUnSortedHashtable;
45 class SrsAmf0ObjectEOF; 45 class SrsAmf0ObjectEOF;
  46 + class SrsAmf0Date;
46 } 47 }
47 48
48 /* 49 /*
@@ -185,6 +186,12 @@ public: @@ -185,6 +186,12 @@ public:
185 */ 186 */
186 virtual bool is_strict_array(); 187 virtual bool is_strict_array();
187 /** 188 /**
  189 + * whether current instance is an AMF0 date.
  190 + * @return true if instance is an AMF0 date; otherwise, false.
  191 + * @remark, if true, use to_date() to get its value.
  192 + */
  193 + virtual bool is_date();
  194 + /**
188 * whether current instance is an AMF0 object, object-EOF, ecma-array or strict-array. 195 * whether current instance is an AMF0 object, object-EOF, ecma-array or strict-array.
189 */ 196 */
190 virtual bool is_complex_object(); 197 virtual bool is_complex_object();
@@ -212,6 +219,12 @@ public: @@ -212,6 +219,12 @@ public:
212 */ 219 */
213 virtual double to_number(); 220 virtual double to_number();
214 /** 221 /**
  222 + * convert instance to date,
  223 + * @remark assert is_date(), user must ensure the type then convert.
  224 + */
  225 + virtual int64_t to_date();
  226 + virtual int16_t to_date_time_zone();
  227 + /**
215 * convert instance to amf0 object, 228 * convert instance to amf0 object,
216 * @remark assert is_object(), user must ensure the type then convert. 229 * @remark assert is_object(), user must ensure the type then convert.
217 */ 230 */
@@ -274,6 +287,10 @@ public: @@ -274,6 +287,10 @@ public:
274 */ 287 */
275 static SrsAmf0Any* number(double value = 0.0); 288 static SrsAmf0Any* number(double value = 0.0);
276 /** 289 /**
  290 + * create an AMF0 date instance
  291 + */
  292 + static SrsAmf0Any* date(int64_t value = 0);
  293 + /**
277 * create an AMF0 null instance 294 * create an AMF0 null instance
278 */ 295 */
279 static SrsAmf0Any* null(); 296 static SrsAmf0Any* null();
@@ -532,6 +549,7 @@ public: @@ -532,6 +549,7 @@ public:
532 static int utf8(std::string value); 549 static int utf8(std::string value);
533 static int str(std::string value); 550 static int str(std::string value);
534 static int number(); 551 static int number();
  552 + static int date();
535 static int null(); 553 static int null();
536 static int undefined(); 554 static int undefined();
537 static int boolean(); 555 static int boolean();
@@ -674,6 +692,43 @@ namespace _srs_internal @@ -674,6 +692,43 @@ namespace _srs_internal
674 }; 692 };
675 693
676 /** 694 /**
  695 + * 2.13 Date Type
  696 + * time-zone = S16 ; reserved, not supported should be set to 0x0000
  697 + * date-type = date-marker DOUBLE time-zone
  698 + * @see: https://github.com/winlinvip/simple-rtmp-server/issues/185
  699 + */
  700 + class SrsAmf0Date : public SrsAmf0Any
  701 + {
  702 + private:
  703 + int64_t _date_value;
  704 + int16_t _time_zone;
  705 + private:
  706 + friend class SrsAmf0Any;
  707 + /**
  708 + * make amf0 date to private,
  709 + * use should never declare it, use SrsAmf0Any::date() to create it.
  710 + */
  711 + SrsAmf0Date(int64_t value);
  712 + public:
  713 + virtual ~SrsAmf0Date();
  714 + // serialize/deserialize to/from stream.
  715 + public:
  716 + virtual int total_size();
  717 + virtual int read(SrsStream* stream);
  718 + virtual int write(SrsStream* stream);
  719 + virtual SrsAmf0Any* copy();
  720 + public:
  721 + /**
  722 + * get the date value.
  723 + */
  724 + virtual int64_t date();
  725 + /**
  726 + * get the time_zone.
  727 + */
  728 + virtual int16_t time_zone();
  729 + };
  730 +
  731 + /**
677 * read amf0 null from stream. 732 * read amf0 null from stream.
678 * 2.7 null Type 733 * 2.7 null Type
679 * null-type = null-marker 734 * null-type = null-marker