正在显示
6 个修改的文件
包含
220 行增加
和
4 行删除
| @@ -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 |
-
请 注册 或 登录 后发表评论