正在显示
13 个修改的文件
包含
157 行增加
和
53 行删除
| @@ -249,11 +249,11 @@ int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0 | @@ -249,11 +249,11 @@ int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0 | ||
| 249 | if (srs_amf0_is_object(amf0_data)) { | 249 | if (srs_amf0_is_object(amf0_data)) { |
| 250 | keyframes = srs_amf0_object_property(amf0_data, "keyframes"); | 250 | keyframes = srs_amf0_object_property(amf0_data, "keyframes"); |
| 251 | if (keyframes == NULL) { | 251 | if (keyframes == NULL) { |
| 252 | - keyframes = srs_amf0_create_ecma_array(); | 252 | + keyframes = srs_amf0_create_object(); |
| 253 | + srs_amf0_object_property_set(amf0_data, "keyframes", keyframes); | ||
| 253 | } | 254 | } |
| 254 | - srs_amf0_object_property_set(amf0_data, "keyframes", keyframes); | ||
| 255 | // always clear the old keyframes. | 255 | // always clear the old keyframes. |
| 256 | - srs_amf0_ecma_array_clear(keyframes); | 256 | + srs_amf0_object_clear(keyframes); |
| 257 | 257 | ||
| 258 | *pfilepositions = filepositions = srs_amf0_create_strict_array(); | 258 | *pfilepositions = filepositions = srs_amf0_create_strict_array(); |
| 259 | srs_amf0_object_property_set(keyframes, "filepositions", filepositions); | 259 | srs_amf0_object_property_set(keyframes, "filepositions", filepositions); |
| @@ -263,17 +263,17 @@ int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0 | @@ -263,17 +263,17 @@ int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0 | ||
| 263 | } else if (srs_amf0_is_ecma_array(amf0_data)) { | 263 | } else if (srs_amf0_is_ecma_array(amf0_data)) { |
| 264 | keyframes = srs_amf0_ecma_array_property(amf0_data, "keyframes"); | 264 | keyframes = srs_amf0_ecma_array_property(amf0_data, "keyframes"); |
| 265 | if (keyframes == NULL) { | 265 | if (keyframes == NULL) { |
| 266 | - keyframes = srs_amf0_create_ecma_array(); | 266 | + keyframes = srs_amf0_create_object(); |
| 267 | + srs_amf0_ecma_array_property_set(amf0_data, "keyframes", keyframes); | ||
| 267 | } | 268 | } |
| 268 | - srs_amf0_ecma_array_property_set(amf0_data, "keyframes", keyframes); | ||
| 269 | // always clear the old keyframes. | 269 | // always clear the old keyframes. |
| 270 | - srs_amf0_ecma_array_clear(keyframes); | 270 | + srs_amf0_object_clear(keyframes); |
| 271 | 271 | ||
| 272 | *pfilepositions = filepositions = srs_amf0_create_strict_array(); | 272 | *pfilepositions = filepositions = srs_amf0_create_strict_array(); |
| 273 | - srs_amf0_ecma_array_property_set(keyframes, "filepositions", filepositions); | 273 | + srs_amf0_object_property_set(keyframes, "filepositions", filepositions); |
| 274 | 274 | ||
| 275 | times = srs_amf0_create_strict_array(); | 275 | times = srs_amf0_create_strict_array(); |
| 276 | - srs_amf0_ecma_array_property_set(keyframes, "times", times); | 276 | + srs_amf0_object_property_set(keyframes, "times", times); |
| 277 | } | 277 | } |
| 278 | } | 278 | } |
| 279 | 279 |
| @@ -152,8 +152,10 @@ int SrsEdgeIngester::cycle() | @@ -152,8 +152,10 @@ int SrsEdgeIngester::cycle() | ||
| 152 | return ret; | 152 | return ret; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | - if ((ret = ingest()) != ERROR_SUCCESS) { | ||
| 156 | - return ret; | 155 | + ret = ingest(); |
| 156 | + if (srs_is_client_gracefully_close(ret)) { | ||
| 157 | + srs_warn("origin disconnected, retry. ret=%d", ret); | ||
| 158 | + ret = ERROR_SUCCESS; | ||
| 157 | } | 159 | } |
| 158 | 160 | ||
| 159 | return ret; | 161 | return ret; |
| @@ -186,7 +188,9 @@ int SrsEdgeIngester::ingest() | @@ -186,7 +188,9 @@ int SrsEdgeIngester::ingest() | ||
| 186 | // read from client. | 188 | // read from client. |
| 187 | SrsMessage* msg = NULL; | 189 | SrsMessage* msg = NULL; |
| 188 | if ((ret = client->recv_message(&msg)) != ERROR_SUCCESS) { | 190 | if ((ret = client->recv_message(&msg)) != ERROR_SUCCESS) { |
| 189 | - srs_error("ingest recv origin server message failed. ret=%d", ret); | 191 | + if (!srs_is_client_gracefully_close(ret)) { |
| 192 | + srs_error("ingest recv origin server message failed. ret=%d", ret); | ||
| 193 | + } | ||
| 190 | return ret; | 194 | return ret; |
| 191 | } | 195 | } |
| 192 | srs_verbose("edge loop recv message. ret=%d", ret); | 196 | srs_verbose("edge loop recv message. ret=%d", ret); |
| @@ -286,11 +290,8 @@ int SrsEdgeIngester::connect_server() | @@ -286,11 +290,8 @@ int SrsEdgeIngester::connect_server() | ||
| 286 | server = server.substr(0, pos); | 290 | server = server.substr(0, pos); |
| 287 | port = ::atoi(s_port.c_str()); | 291 | port = ::atoi(s_port.c_str()); |
| 288 | } | 292 | } |
| 289 | - | ||
| 290 | - // open socket. | ||
| 291 | - srs_trace("edge connected, can_publish=%d, url=%s/%s, server=%s:%d", | ||
| 292 | - _source->can_publish(), _req->tcUrl.c_str(), _req->stream.c_str(), server.c_str(), port); | ||
| 293 | 293 | ||
| 294 | + // open socket. | ||
| 294 | // TODO: FIXME: extract utility method | 295 | // TODO: FIXME: extract utility method |
| 295 | int sock = socket(AF_INET, SOCK_STREAM, 0); | 296 | int sock = socket(AF_INET, SOCK_STREAM, 0); |
| 296 | if(sock == -1){ | 297 | if(sock == -1){ |
| @@ -332,7 +333,10 @@ int SrsEdgeIngester::connect_server() | @@ -332,7 +333,10 @@ int SrsEdgeIngester::connect_server() | ||
| 332 | srs_error("connect to server error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret); | 333 | srs_error("connect to server error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret); |
| 333 | return ret; | 334 | return ret; |
| 334 | } | 335 | } |
| 335 | - srs_trace("connect to server success. server=%s, ip=%s, port=%d", server.c_str(), ip.c_str(), port); | 336 | + srs_info("connect to server success. server=%s, ip=%s, port=%d", server.c_str(), ip.c_str(), port); |
| 337 | + | ||
| 338 | + srs_trace("edge connected, can_publish=%d, url=%s/%s, server=%s:%d", | ||
| 339 | + _source->can_publish(), _req->tcUrl.c_str(), _req->stream.c_str(), server.c_str(), port); | ||
| 336 | 340 | ||
| 337 | return ret; | 341 | return ret; |
| 338 | } | 342 | } |
| @@ -99,7 +99,7 @@ int SrsRtmpConn::do_cycle() | @@ -99,7 +99,7 @@ int SrsRtmpConn::do_cycle() | ||
| 99 | { | 99 | { |
| 100 | int ret = ERROR_SUCCESS; | 100 | int ret = ERROR_SUCCESS; |
| 101 | 101 | ||
| 102 | - srs_trace("serve client, peer ip=%s", ip.c_str()); | 102 | + srs_trace("serve client ip=%s", ip.c_str()); |
| 103 | 103 | ||
| 104 | rtmp->set_recv_timeout(SRS_RECV_TIMEOUT_US); | 104 | rtmp->set_recv_timeout(SRS_RECV_TIMEOUT_US); |
| 105 | rtmp->set_send_timeout(SRS_SEND_TIMEOUT_US); | 105 | rtmp->set_send_timeout(SRS_SEND_TIMEOUT_US); |
| @@ -140,7 +140,7 @@ int SrsRtmpConn::do_cycle() | @@ -140,7 +140,7 @@ int SrsRtmpConn::do_cycle() | ||
| 140 | } | 140 | } |
| 141 | srs_verbose("check vhost success."); | 141 | srs_verbose("check vhost success."); |
| 142 | 142 | ||
| 143 | - srs_trace("rtmp connect app success. " | 143 | + srs_trace("connect app, " |
| 144 | "tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s", | 144 | "tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s", |
| 145 | req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(), | 145 | req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(), |
| 146 | req->schema.c_str(), req->vhost.c_str(), req->port.c_str(), | 146 | req->schema.c_str(), req->vhost.c_str(), req->port.c_str(), |
| @@ -254,11 +254,13 @@ int SrsRtmpConn::stream_service_cycle() | @@ -254,11 +254,13 @@ int SrsRtmpConn::stream_service_cycle() | ||
| 254 | 254 | ||
| 255 | SrsRtmpConnType type; | 255 | SrsRtmpConnType type; |
| 256 | if ((ret = rtmp->identify_client(res->stream_id, type, req->stream, req->duration)) != ERROR_SUCCESS) { | 256 | if ((ret = rtmp->identify_client(res->stream_id, type, req->stream, req->duration)) != ERROR_SUCCESS) { |
| 257 | - srs_error("identify client failed. ret=%d", ret); | 257 | + if (!srs_is_client_gracefully_close(ret)) { |
| 258 | + srs_error("identify client failed. ret=%d", ret); | ||
| 259 | + } | ||
| 258 | return ret; | 260 | return ret; |
| 259 | } | 261 | } |
| 260 | req->strip(); | 262 | req->strip(); |
| 261 | - srs_trace("identify client success. type=%s, stream_name=%s, duration=%.2f", | 263 | + srs_trace("client identified, type=%s, stream_name=%s, duration=%.2f", |
| 262 | srs_client_type_string(type).c_str(), req->stream.c_str(), req->duration); | 264 | srs_client_type_string(type).c_str(), req->stream.c_str(), req->duration); |
| 263 | 265 | ||
| 264 | // client is identified, set the timeout to service timeout. | 266 | // client is identified, set the timeout to service timeout. |
| @@ -23,6 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -23,6 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | 23 | ||
| 24 | #include <srs_app_source.hpp> | 24 | #include <srs_app_source.hpp> |
| 25 | 25 | ||
| 26 | +#include <sstream> | ||
| 26 | #include <algorithm> | 27 | #include <algorithm> |
| 27 | using namespace std; | 28 | using namespace std; |
| 28 | 29 | ||
| @@ -850,11 +851,28 @@ int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata) | @@ -850,11 +851,28 @@ int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata) | ||
| 850 | return ret; | 851 | return ret; |
| 851 | } | 852 | } |
| 852 | #endif | 853 | #endif |
| 854 | + | ||
| 855 | + SrsAmf0Any* prop = NULL; | ||
| 856 | + | ||
| 857 | + // generate metadata info to print | ||
| 858 | + std::stringstream ss; | ||
| 859 | + if ((prop = metadata->metadata->ensure_property_number("width")) != NULL) { | ||
| 860 | + ss << ", width=" << (int)prop->to_number(); | ||
| 861 | + } | ||
| 862 | + if ((prop = metadata->metadata->ensure_property_number("height")) != NULL) { | ||
| 863 | + ss << ", height=" << (int)prop->to_number(); | ||
| 864 | + } | ||
| 865 | + if ((prop = metadata->metadata->ensure_property_number("videocodecid")) != NULL) { | ||
| 866 | + ss << ", vcodec=" << (int)prop->to_number(); | ||
| 867 | + } | ||
| 868 | + if ((prop = metadata->metadata->ensure_property_number("audiocodecid")) != NULL) { | ||
| 869 | + ss << ", acodec=" << (int)prop->to_number(); | ||
| 870 | + } | ||
| 853 | 871 | ||
| 872 | + // add server info to metadata | ||
| 854 | metadata->metadata->set("server", SrsAmf0Any::str(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")")); | 873 | metadata->metadata->set("server", SrsAmf0Any::str(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")")); |
| 855 | metadata->metadata->set("authors", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY_AUTHROS)); | 874 | metadata->metadata->set("authors", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY_AUTHROS)); |
| 856 | 875 | ||
| 857 | - SrsAmf0Any* prop = NULL; | ||
| 858 | if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) { | 876 | if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) { |
| 859 | if (prop->is_number()) { | 877 | if (prop->is_number()) { |
| 860 | sample_rate = (int)prop->to_number(); | 878 | sample_rate = (int)prop->to_number(); |
| @@ -912,7 +930,7 @@ int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata) | @@ -912,7 +930,7 @@ int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata) | ||
| 912 | return ret; | 930 | return ret; |
| 913 | } | 931 | } |
| 914 | } | 932 | } |
| 915 | - srs_trace("dispatch metadata success."); | 933 | + srs_trace("got metadata%s", ss.str().c_str()); |
| 916 | } | 934 | } |
| 917 | 935 | ||
| 918 | // copy to all forwarders | 936 | // copy to all forwarders |
| @@ -996,7 +1014,7 @@ int SrsSource::on_audio(SrsMessage* audio) | @@ -996,7 +1014,7 @@ int SrsSource::on_audio(SrsMessage* audio) | ||
| 996 | if (SrsCodec::audio_is_sequence_header(msg->payload, msg->size)) { | 1014 | if (SrsCodec::audio_is_sequence_header(msg->payload, msg->size)) { |
| 997 | srs_freep(cache_sh_audio); | 1015 | srs_freep(cache_sh_audio); |
| 998 | cache_sh_audio = msg->copy(); | 1016 | cache_sh_audio = msg->copy(); |
| 999 | - srs_trace("update audio sequence header success. size=%d", msg->header.payload_length); | 1017 | + srs_trace("got audio sh, size=%d", msg->header.payload_length); |
| 1000 | return ret; | 1018 | return ret; |
| 1001 | } | 1019 | } |
| 1002 | 1020 | ||
| @@ -1086,7 +1104,7 @@ int SrsSource::on_video(SrsMessage* video) | @@ -1086,7 +1104,7 @@ int SrsSource::on_video(SrsMessage* video) | ||
| 1086 | if (SrsCodec::video_is_sequence_header(msg->payload, msg->size)) { | 1104 | if (SrsCodec::video_is_sequence_header(msg->payload, msg->size)) { |
| 1087 | srs_freep(cache_sh_video); | 1105 | srs_freep(cache_sh_video); |
| 1088 | cache_sh_video = msg->copy(); | 1106 | cache_sh_video = msg->copy(); |
| 1089 | - srs_trace("update video sequence header success. size=%d", msg->header.payload_length); | 1107 | + srs_trace("got video sh, size=%d", msg->header.payload_length); |
| 1090 | return ret; | 1108 | return ret; |
| 1091 | } | 1109 | } |
| 1092 | 1110 | ||
| @@ -1277,7 +1295,8 @@ void SrsSource::on_unpublish() | @@ -1277,7 +1295,8 @@ void SrsSource::on_unpublish() | ||
| 1277 | srs_freep(cache_sh_video); | 1295 | srs_freep(cache_sh_video); |
| 1278 | srs_freep(cache_sh_audio); | 1296 | srs_freep(cache_sh_audio); |
| 1279 | 1297 | ||
| 1280 | - srs_trace("clear cache/metadata/sequence-headers when unpublish."); | 1298 | + srs_info("clear cache/metadata/sequence-headers when unpublish."); |
| 1299 | + srs_trace("cleanup when unpublish"); | ||
| 1281 | 1300 | ||
| 1282 | _can_publish = true; | 1301 | _can_publish = true; |
| 1283 | _source_id = -1; | 1302 | _source_id = -1; |
| @@ -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 "0" | 32 | #define VERSION_MAJOR "0" |
| 33 | #define VERSION_MINOR "9" | 33 | #define VERSION_MINOR "9" |
| 34 | -#define VERSION_REVISION "122" | 34 | +#define VERSION_REVISION "123" |
| 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" |
| @@ -594,6 +594,11 @@ srs_amf0_t srs_amf0_create_strict_array() | @@ -594,6 +594,11 @@ srs_amf0_t srs_amf0_create_strict_array() | ||
| 594 | return SrsAmf0Any::strict_array(); | 594 | return SrsAmf0Any::strict_array(); |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | +srs_amf0_t srs_amf0_create_object() | ||
| 598 | +{ | ||
| 599 | + return SrsAmf0Any::object(); | ||
| 600 | +} | ||
| 601 | + | ||
| 597 | void srs_amf0_free(srs_amf0_t amf0) | 602 | void srs_amf0_free(srs_amf0_t amf0) |
| 598 | { | 603 | { |
| 599 | SrsAmf0Any* any = (SrsAmf0Any*)amf0; | 604 | SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| @@ -697,88 +702,130 @@ void srs_amf0_set_number(srs_amf0_t amf0, amf0_number value) | @@ -697,88 +702,130 @@ void srs_amf0_set_number(srs_amf0_t amf0, amf0_number value) | ||
| 697 | 702 | ||
| 698 | int srs_amf0_object_property_count(srs_amf0_t amf0) | 703 | int srs_amf0_object_property_count(srs_amf0_t amf0) |
| 699 | { | 704 | { |
| 705 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 706 | + srs_assert(any->is_object()); | ||
| 707 | + | ||
| 700 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | 708 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 701 | return obj->count(); | 709 | return obj->count(); |
| 702 | } | 710 | } |
| 703 | 711 | ||
| 704 | const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index) | 712 | const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index) |
| 705 | { | 713 | { |
| 714 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 715 | + srs_assert(any->is_object()); | ||
| 716 | + | ||
| 706 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | 717 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 707 | return obj->key_raw_at(index); | 718 | return obj->key_raw_at(index); |
| 708 | } | 719 | } |
| 709 | 720 | ||
| 710 | srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) | 721 | srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) |
| 711 | { | 722 | { |
| 723 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 724 | + srs_assert(any->is_object()); | ||
| 725 | + | ||
| 712 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | 726 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 713 | return (srs_amf0_t)obj->value_at(index); | 727 | return (srs_amf0_t)obj->value_at(index); |
| 714 | } | 728 | } |
| 715 | 729 | ||
| 716 | srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name) | 730 | srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name) |
| 717 | { | 731 | { |
| 732 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 733 | + srs_assert(any->is_object()); | ||
| 734 | + | ||
| 718 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | 735 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 719 | return (srs_amf0_t)obj->get_property(name); | 736 | return (srs_amf0_t)obj->get_property(name); |
| 720 | } | 737 | } |
| 721 | 738 | ||
| 722 | void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) | 739 | void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) |
| 723 | { | 740 | { |
| 741 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 742 | + srs_assert(any->is_object()); | ||
| 743 | + | ||
| 724 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | 744 | SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 725 | - SrsAmf0Any* any = (SrsAmf0Any*)value; | 745 | + any = (SrsAmf0Any*)value; |
| 726 | obj->set(name, any); | 746 | obj->set(name, any); |
| 727 | } | 747 | } |
| 728 | 748 | ||
| 749 | +void srs_amf0_object_clear(srs_amf0_t amf0) | ||
| 750 | +{ | ||
| 751 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 752 | + srs_assert(any->is_object()); | ||
| 753 | + | ||
| 754 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 755 | + obj->clear(); | ||
| 756 | +} | ||
| 757 | + | ||
| 729 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) | 758 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) |
| 730 | { | 759 | { |
| 760 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 761 | + srs_assert(any->is_ecma_array()); | ||
| 762 | + | ||
| 731 | SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; | 763 | SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; |
| 732 | return obj->count(); | 764 | return obj->count(); |
| 733 | } | 765 | } |
| 734 | 766 | ||
| 735 | const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index) | 767 | const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index) |
| 736 | { | 768 | { |
| 769 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 770 | + srs_assert(any->is_ecma_array()); | ||
| 771 | + | ||
| 737 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | 772 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; |
| 738 | return obj->key_raw_at(index); | 773 | return obj->key_raw_at(index); |
| 739 | } | 774 | } |
| 740 | 775 | ||
| 741 | srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) | 776 | srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) |
| 742 | { | 777 | { |
| 778 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 779 | + srs_assert(any->is_ecma_array()); | ||
| 780 | + | ||
| 743 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | 781 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; |
| 744 | return (srs_amf0_t)obj->value_at(index); | 782 | return (srs_amf0_t)obj->value_at(index); |
| 745 | } | 783 | } |
| 746 | 784 | ||
| 747 | srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name) | 785 | srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name) |
| 748 | { | 786 | { |
| 787 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 788 | + srs_assert(any->is_ecma_array()); | ||
| 789 | + | ||
| 749 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | 790 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; |
| 750 | return (srs_amf0_t)obj->get_property(name); | 791 | return (srs_amf0_t)obj->get_property(name); |
| 751 | } | 792 | } |
| 752 | 793 | ||
| 753 | void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) | 794 | void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) |
| 754 | { | 795 | { |
| 755 | - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 756 | - SrsAmf0Any* any = (SrsAmf0Any*)value; | ||
| 757 | - obj->set(name, any); | ||
| 758 | -} | 796 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| 797 | + srs_assert(any->is_ecma_array()); | ||
| 759 | 798 | ||
| 760 | -void srs_amf0_ecma_array_clear(srs_amf0_t amf0) | ||
| 761 | -{ | ||
| 762 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | 799 | SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; |
| 763 | - obj->clear(); | 800 | + any = (SrsAmf0Any*)value; |
| 801 | + obj->set(name, any); | ||
| 764 | } | 802 | } |
| 765 | 803 | ||
| 766 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0) | 804 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0) |
| 767 | { | 805 | { |
| 806 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 807 | + srs_assert(any->is_strict_array()); | ||
| 808 | + | ||
| 768 | SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0; | 809 | SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0; |
| 769 | return obj->count(); | 810 | return obj->count(); |
| 770 | } | 811 | } |
| 771 | 812 | ||
| 772 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) | 813 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) |
| 773 | { | 814 | { |
| 815 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 816 | + srs_assert(any->is_strict_array()); | ||
| 817 | + | ||
| 774 | SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; | 818 | SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; |
| 775 | return (srs_amf0_t)obj->at(index); | 819 | return (srs_amf0_t)obj->at(index); |
| 776 | } | 820 | } |
| 777 | 821 | ||
| 778 | void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) | 822 | void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) |
| 779 | { | 823 | { |
| 824 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 825 | + srs_assert(any->is_strict_array()); | ||
| 826 | + | ||
| 780 | SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; | 827 | SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; |
| 781 | - SrsAmf0Any* any = (SrsAmf0Any*)value; | 828 | + any = (SrsAmf0Any*)value; |
| 782 | obj->append(any); | 829 | obj->append(any); |
| 783 | } | 830 | } |
| 784 | 831 |
| @@ -196,6 +196,7 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); | @@ -196,6 +196,7 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); | ||
| 196 | srs_amf0_t srs_amf0_create_number(amf0_number value); | 196 | srs_amf0_t srs_amf0_create_number(amf0_number value); |
| 197 | srs_amf0_t srs_amf0_create_ecma_array(); | 197 | srs_amf0_t srs_amf0_create_ecma_array(); |
| 198 | srs_amf0_t srs_amf0_create_strict_array(); | 198 | srs_amf0_t srs_amf0_create_strict_array(); |
| 199 | +srs_amf0_t srs_amf0_create_object(); | ||
| 199 | void srs_amf0_free(srs_amf0_t amf0); | 200 | void srs_amf0_free(srs_amf0_t amf0); |
| 200 | void srs_amf0_free_bytes(char* data); | 201 | void srs_amf0_free_bytes(char* data); |
| 201 | /* size and to bytes */ | 202 | /* size and to bytes */ |
| @@ -221,13 +222,13 @@ const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); | @@ -221,13 +222,13 @@ const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); | ||
| 221 | srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); | 222 | srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); |
| 222 | srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); | 223 | srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); |
| 223 | void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | 224 | void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); |
| 225 | +void srs_amf0_object_clear(srs_amf0_t amf0); | ||
| 224 | /* ecma array value converter */ | 226 | /* ecma array value converter */ |
| 225 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); | 227 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); |
| 226 | const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); | 228 | const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); |
| 227 | srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); | 229 | srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); |
| 228 | srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); | 230 | srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); |
| 229 | void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | 231 | void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); |
| 230 | -void srs_amf0_ecma_array_clear(srs_amf0_t amf0); | ||
| 231 | /* strict array value converter */ | 232 | /* strict array value converter */ |
| 232 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0); | 233 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0); |
| 233 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); | 234 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); |
| @@ -788,6 +788,11 @@ SrsAmf0Any* SrsAmf0Object::copy() | @@ -788,6 +788,11 @@ SrsAmf0Any* SrsAmf0Object::copy() | ||
| 788 | return copy; | 788 | return copy; |
| 789 | } | 789 | } |
| 790 | 790 | ||
| 791 | +void SrsAmf0Object::clear() | ||
| 792 | +{ | ||
| 793 | + properties->clear(); | ||
| 794 | +} | ||
| 795 | + | ||
| 791 | int SrsAmf0Object::count() | 796 | int SrsAmf0Object::count() |
| 792 | { | 797 | { |
| 793 | return properties->count(); | 798 | return properties->count(); |
| @@ -190,6 +190,7 @@ public: | @@ -190,6 +190,7 @@ public: | ||
| 190 | virtual SrsAmf0Any* copy(); | 190 | virtual SrsAmf0Any* copy(); |
| 191 | 191 | ||
| 192 | public: | 192 | public: |
| 193 | + virtual void clear(); | ||
| 193 | virtual int count(); | 194 | virtual int count(); |
| 194 | // @remark: max index is count(). | 195 | // @remark: max index is count(). |
| 195 | virtual std::string key_at(int index); | 196 | virtual std::string key_at(int index); |
| @@ -1041,7 +1041,7 @@ int SrsSimpleHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsP | @@ -1041,7 +1041,7 @@ int SrsSimpleHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsP | ||
| 1041 | return ret; | 1041 | return ret; |
| 1042 | } | 1042 | } |
| 1043 | 1043 | ||
| 1044 | - srs_trace("simple handshake with client success."); | 1044 | + srs_trace("simple handshake success."); |
| 1045 | 1045 | ||
| 1046 | return ret; | 1046 | return ret; |
| 1047 | } | 1047 | } |
| @@ -1083,7 +1083,7 @@ int SrsSimpleHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsP | @@ -1083,7 +1083,7 @@ int SrsSimpleHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsP | ||
| 1083 | } | 1083 | } |
| 1084 | srs_verbose("simple handshake write c2 success."); | 1084 | srs_verbose("simple handshake write c2 success."); |
| 1085 | 1085 | ||
| 1086 | - srs_trace("simple handshake with server success."); | 1086 | + srs_trace("simple handshake success."); |
| 1087 | 1087 | ||
| 1088 | return ret; | 1088 | return ret; |
| 1089 | } | 1089 | } |
| @@ -1189,7 +1189,7 @@ int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrs | @@ -1189,7 +1189,7 @@ int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrs | ||
| 1189 | // never verify c2, for ffmpeg will failed. | 1189 | // never verify c2, for ffmpeg will failed. |
| 1190 | // it's ok for flash. | 1190 | // it's ok for flash. |
| 1191 | 1191 | ||
| 1192 | - srs_trace("complex handshake with client success"); | 1192 | + srs_trace("complex handshake success"); |
| 1193 | 1193 | ||
| 1194 | return ret; | 1194 | return ret; |
| 1195 | } | 1195 | } |
| @@ -1269,7 +1269,7 @@ int SrsComplexHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrs | @@ -1269,7 +1269,7 @@ int SrsComplexHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrs | ||
| 1269 | } | 1269 | } |
| 1270 | srs_verbose("complex handshake write c2 success."); | 1270 | srs_verbose("complex handshake write c2 success."); |
| 1271 | 1271 | ||
| 1272 | - srs_trace("complex handshake with server success."); | 1272 | + srs_trace("complex handshake success."); |
| 1273 | 1273 | ||
| 1274 | return ret; | 1274 | return ret; |
| 1275 | } | 1275 | } |
| @@ -947,15 +947,22 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& | @@ -947,15 +947,22 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& | ||
| 947 | while (true) { | 947 | while (true) { |
| 948 | SrsMessage* msg = NULL; | 948 | SrsMessage* msg = NULL; |
| 949 | if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { | 949 | if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { |
| 950 | - srs_error("recv identify client message failed. ret=%d", ret); | 950 | + if (!srs_is_client_gracefully_close(ret)) { |
| 951 | + srs_error("recv identify client message failed. ret=%d", ret); | ||
| 952 | + } | ||
| 951 | return ret; | 953 | return ret; |
| 952 | } | 954 | } |
| 953 | 955 | ||
| 954 | SrsAutoFree(SrsMessage, msg); | 956 | SrsAutoFree(SrsMessage, msg); |
| 955 | - | ||
| 956 | - if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) { | 957 | + SrsMessageHeader& h = msg->header; |
| 958 | + | ||
| 959 | + if (h.is_ackledgement() || h.is_set_chunk_size() || h.is_window_ackledgement_size() || h.is_user_control_message()) { | ||
| 960 | + continue; | ||
| 961 | + } | ||
| 962 | + | ||
| 963 | + if (!h.is_amf0_command() && !h.is_amf3_command()) { | ||
| 957 | srs_trace("identify ignore messages except " | 964 | srs_trace("identify ignore messages except " |
| 958 | - "AMF0/AMF3 command message. type=%#x", msg->header.message_type); | 965 | + "AMF0/AMF3 command message. type=%#x", h.message_type); |
| 959 | continue; | 966 | continue; |
| 960 | } | 967 | } |
| 961 | 968 | ||
| @@ -1335,15 +1342,22 @@ int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int | @@ -1335,15 +1342,22 @@ int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int | ||
| 1335 | while (true) { | 1342 | while (true) { |
| 1336 | SrsMessage* msg = NULL; | 1343 | SrsMessage* msg = NULL; |
| 1337 | if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { | 1344 | if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { |
| 1338 | - srs_error("recv identify client message failed. ret=%d", ret); | 1345 | + if (!srs_is_client_gracefully_close(ret)) { |
| 1346 | + srs_error("recv identify client message failed. ret=%d", ret); | ||
| 1347 | + } | ||
| 1339 | return ret; | 1348 | return ret; |
| 1340 | } | 1349 | } |
| 1341 | 1350 | ||
| 1342 | SrsAutoFree(SrsMessage, msg); | 1351 | SrsAutoFree(SrsMessage, msg); |
| 1343 | - | ||
| 1344 | - if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) { | 1352 | + SrsMessageHeader& h = msg->header; |
| 1353 | + | ||
| 1354 | + if (h.is_ackledgement() || h.is_set_chunk_size() || h.is_window_ackledgement_size() || h.is_user_control_message()) { | ||
| 1355 | + continue; | ||
| 1356 | + } | ||
| 1357 | + | ||
| 1358 | + if (!h.is_amf0_command() && !h.is_amf3_command()) { | ||
| 1345 | srs_trace("identify ignore messages except " | 1359 | srs_trace("identify ignore messages except " |
| 1346 | - "AMF0/AMF3 command message. type=%#x", msg->header.message_type); | 1360 | + "AMF0/AMF3 command message. type=%#x", h.message_type); |
| 1347 | continue; | 1361 | continue; |
| 1348 | } | 1362 | } |
| 1349 | 1363 | ||
| @@ -1408,7 +1422,7 @@ int SrsRtmpServer::identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& typ | @@ -1408,7 +1422,7 @@ int SrsRtmpServer::identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& typ | ||
| 1408 | stream_name = req->stream_name; | 1422 | stream_name = req->stream_name; |
| 1409 | duration = req->duration; | 1423 | duration = req->duration; |
| 1410 | 1424 | ||
| 1411 | - srs_trace("identity client type=play, stream_name=%s, duration=%.2f", stream_name.c_str(), duration); | 1425 | + srs_info("identity client type=play, stream_name=%s, duration=%.2f", stream_name.c_str(), duration); |
| 1412 | 1426 | ||
| 1413 | return ret; | 1427 | return ret; |
| 1414 | } | 1428 | } |
| @@ -719,7 +719,9 @@ int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, | @@ -719,7 +719,9 @@ int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, | ||
| 719 | *ppacket = packet = new SrsSetChunkSizePacket(); | 719 | *ppacket = packet = new SrsSetChunkSizePacket(); |
| 720 | return packet->decode(stream); | 720 | return packet->decode(stream); |
| 721 | } else { | 721 | } else { |
| 722 | - srs_trace("drop unknown message, type=%d", header.message_type); | 722 | + if (!header.is_set_peer_bandwidth()) { |
| 723 | + srs_trace("drop unknown message, type=%d", header.message_type); | ||
| 724 | + } | ||
| 723 | } | 725 | } |
| 724 | 726 | ||
| 725 | return ret; | 727 | return ret; |
| @@ -1289,7 +1291,10 @@ int SrsProtocol::on_recv_message(SrsMessage* msg) | @@ -1289,7 +1291,10 @@ int SrsProtocol::on_recv_message(SrsMessage* msg) | ||
| 1289 | 1291 | ||
| 1290 | if (pkt->ackowledgement_window_size > 0) { | 1292 | if (pkt->ackowledgement_window_size > 0) { |
| 1291 | in_ack_size.ack_window_size = pkt->ackowledgement_window_size; | 1293 | in_ack_size.ack_window_size = pkt->ackowledgement_window_size; |
| 1292 | - srs_trace("set ack window size to %d", pkt->ackowledgement_window_size); | 1294 | + // @remakr, we ignore this message, for user noneed to care. |
| 1295 | + // but it's important for dev, for client/server will block if required | ||
| 1296 | + // ack msg not arrived. | ||
| 1297 | + srs_info("set ack window size to %d", pkt->ackowledgement_window_size); | ||
| 1293 | } else { | 1298 | } else { |
| 1294 | srs_warn("ignored. set ack window size is %d", pkt->ackowledgement_window_size); | 1299 | srs_warn("ignored. set ack window size is %d", pkt->ackowledgement_window_size); |
| 1295 | } | 1300 | } |
| @@ -1301,7 +1306,7 @@ int SrsProtocol::on_recv_message(SrsMessage* msg) | @@ -1301,7 +1306,7 @@ int SrsProtocol::on_recv_message(SrsMessage* msg) | ||
| 1301 | 1306 | ||
| 1302 | in_chunk_size = pkt->chunk_size; | 1307 | in_chunk_size = pkt->chunk_size; |
| 1303 | 1308 | ||
| 1304 | - srs_trace("set input chunk size to %d", pkt->chunk_size); | 1309 | + srs_trace("input chunk size to %d", pkt->chunk_size); |
| 1305 | break; | 1310 | break; |
| 1306 | } | 1311 | } |
| 1307 | case RTMP_MSG_UserControlMessage: { | 1312 | case RTMP_MSG_UserControlMessage: { |
| @@ -1339,7 +1344,7 @@ int SrsProtocol::on_send_message(SrsMessage* msg, SrsPacket* packet) | @@ -1339,7 +1344,7 @@ int SrsProtocol::on_send_message(SrsMessage* msg, SrsPacket* packet) | ||
| 1339 | 1344 | ||
| 1340 | out_chunk_size = pkt->chunk_size; | 1345 | out_chunk_size = pkt->chunk_size; |
| 1341 | 1346 | ||
| 1342 | - srs_trace("set output chunk size to %d", pkt->chunk_size); | 1347 | + srs_trace("out chunk size to %d", pkt->chunk_size); |
| 1343 | break; | 1348 | break; |
| 1344 | } | 1349 | } |
| 1345 | case RTMP_MSG_AMF0CommandMessage: | 1350 | case RTMP_MSG_AMF0CommandMessage: |
| @@ -1473,6 +1478,11 @@ bool SrsMessageHeader::is_user_control_message() | @@ -1473,6 +1478,11 @@ bool SrsMessageHeader::is_user_control_message() | ||
| 1473 | return message_type == RTMP_MSG_UserControlMessage; | 1478 | return message_type == RTMP_MSG_UserControlMessage; |
| 1474 | } | 1479 | } |
| 1475 | 1480 | ||
| 1481 | +bool SrsMessageHeader::is_set_peer_bandwidth() | ||
| 1482 | +{ | ||
| 1483 | + return message_type == RTMP_MSG_SetPeerBandwidth; | ||
| 1484 | +} | ||
| 1485 | + | ||
| 1476 | bool SrsMessageHeader::is_aggregate() | 1486 | bool SrsMessageHeader::is_aggregate() |
| 1477 | { | 1487 | { |
| 1478 | return message_type == RTMP_MSG_AggregateMessage; | 1488 | return message_type == RTMP_MSG_AggregateMessage; |
| @@ -278,6 +278,7 @@ public: | @@ -278,6 +278,7 @@ public: | ||
| 278 | bool is_ackledgement(); | 278 | bool is_ackledgement(); |
| 279 | bool is_set_chunk_size(); | 279 | bool is_set_chunk_size(); |
| 280 | bool is_user_control_message(); | 280 | bool is_user_control_message(); |
| 281 | + bool is_set_peer_bandwidth(); | ||
| 281 | bool is_aggregate(); | 282 | bool is_aggregate(); |
| 282 | 283 | ||
| 283 | void initialize_amf0_script(int size, int stream); | 284 | void initialize_amf0_script(int size, int stream); |
-
请 注册 或 登录 后发表评论