diff --git a/README.md b/README.md index 7abe0bcd6..a92d7a27e 100755 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ Remark: ## History +* v2.0, 2015-08-18, close [#454](https://github.com/simple-rtmp-server/srs/issues/454), support obs restart publish. 2.0.184 * v2.0, 2015-08-14, use reduce_sequence_header for stream control. * v2.0, 2015-08-14, use send_min_interval for stream control. 2.0.183 * v2.0, 2015-08-12, enable the SRS_PERF_TCP_NODELAY and add config tcp_nodelay. 2.0.182 diff --git a/trunk/configure b/trunk/configure index d705c6ceb..f11cd25e7 100755 --- a/trunk/configure +++ b/trunk/configure @@ -508,10 +508,15 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then else echo -e "${YELLOW}warning: without HLS support${BLACK}" fi - if [ $SRS_HDS = YES ]; then - echo -e "${GREEN}HDS is enabled${BLACK}" + if [ $SRS_STREAM_CASTER = YES ]; then + echo -e "${YELLOW}Experiment: StreamCaster is enabled${BLACK}" else - echo -e "${YELLOW}warning: without HDS support${BLACK}" + echo -e "${GREEN}note: without StreamCaster support${BLACK}" + fi + if [ $SRS_HDS = YES ]; then + echo -e "${YELLOW}Experiment: HDS is enabled${BLACK}" + else + echo -e "${GREEN}warning: without HDS support${BLACK}" fi if [ $SRS_NGINX = YES ]; then echo -e "${GREEN}Nginx http server is enabled${BLACK}" diff --git a/trunk/src/app/srs_app_recv_thread.cpp b/trunk/src/app/srs_app_recv_thread.cpp index e402643d4..e94b622dd 100644 --- a/trunk/src/app/srs_app_recv_thread.cpp +++ b/trunk/src/app/srs_app_recv_thread.cpp @@ -96,7 +96,7 @@ int SrsRecvThread::cycle() } if (ret != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { + if (!srs_is_client_gracefully_close(ret) && !srs_is_system_control_error(ret)) { srs_error("thread process message failed. ret=%d", ret); } diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index f63456abb..43c3951a9 100755 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -337,6 +337,16 @@ int SrsRtmpConn::service_cycle() } } + // set chunk size to larger. + // set the chunk size before any larger response greater than 128, + // to make OBS happy, @see https://github.com/simple-rtmp-server/srs/issues/454 + int chunk_size = _srs_config->get_chunk_size(req->vhost); + if ((ret = rtmp->set_chunk_size(chunk_size)) != ERROR_SUCCESS) { + srs_error("set chunk_size=%d failed. ret=%d", chunk_size, ret); + return ret; + } + srs_info("set chunk_size=%d success", chunk_size); + // response the client connect ok. if ((ret = rtmp->response_connect_app(req, local_ip.c_str())) != ERROR_SUCCESS) { srs_error("response connect app failed. ret=%d", ret); @@ -424,14 +434,6 @@ int SrsRtmpConn::stream_service_cycle() rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US); rtmp->set_send_timeout(SRS_CONSTS_RTMP_SEND_TIMEOUT_US); - // set chunk size to larger. - int chunk_size = _srs_config->get_chunk_size(req->vhost); - if ((ret = rtmp->set_chunk_size(chunk_size)) != ERROR_SUCCESS) { - srs_error("set chunk_size=%d failed. ret=%d", chunk_size, ret); - return ret; - } - srs_info("set chunk_size=%d success", chunk_size); - // find a source to serve. SrsSource* source = SrsSource::fetch(req); if (!source) { @@ -637,7 +639,7 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, SrsQueueRe // quit when recv thread error. if ((ret = trd->error_code()) != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { + if (!srs_is_client_gracefully_close(ret) && !srs_is_system_control_error(ret)) { srs_error("recv thread failed. ret=%d", ret); } return ret; @@ -824,7 +826,7 @@ int SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* trd) // check the thread error code. if ((ret = trd->error_code()) != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { + if (!srs_is_system_control_error(ret) && !srs_is_client_gracefully_close(ret)) { srs_error("recv thread failed. ret=%d", ret); } return ret; diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 35661bd9c..e8063b85e 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1463,7 +1463,11 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata srs_verbose("initialize shared ptr metadata success."); // copy to all consumer - if (true) { + bool drop_for_reduce = false; + if (cache_metadata && _srs_config->get_reduce_sequence_header(_req->vhost)) { + drop_for_reduce = true; + } + if (!drop_for_reduce) { std::vector::iterator it; for (it = consumers.begin(); it != consumers.end(); ++it) { SrsConsumer* consumer = *it; @@ -2084,10 +2088,10 @@ void SrsSource::on_unpublish() hds->on_unpublish(); #endif - // only clear the gop cache metadata, - // donot clear the sequence header, for it maybe not changed. + // only clear the gop cache, + // donot clear the sequence header, for it maybe not changed, + // when drop dup sequence header, drop the metadata also. gop_cache->clear(); - srs_freep(cache_metadata); srs_info("clear cache/metadata when unpublish."); srs_trace("cleanup when unpublish"); diff --git a/trunk/src/app/srs_app_thread.cpp b/trunk/src/app/srs_app_thread.cpp index 0007df3ea..097758563 100644 --- a/trunk/src/app/srs_app_thread.cpp +++ b/trunk/src/app/srs_app_thread.cpp @@ -187,7 +187,7 @@ namespace internal { srs_info("thread %s on before cycle success"); if ((ret = handler->cycle()) != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { + if (!srs_is_client_gracefully_close(ret) && !srs_is_system_control_error(ret)) { srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret); } goto failed; diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp index d3658999f..0a169d64a 100644 --- a/trunk/src/protocol/srs_rtmp_stack.cpp +++ b/trunk/src/protocol/srs_rtmp_stack.cpp @@ -2924,7 +2924,9 @@ int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid) pkt->data->set(StatusDescription, SrsAmf0Any::str("Stop publishing stream.")); if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onFCUnpublish(NetStream.unpublish.Success) message failed. ret=%d", ret); + if (!srs_is_system_control_error(ret) && !srs_is_client_gracefully_close(ret)) { + srs_error("send onFCUnpublish(NetStream.unpublish.Success) message failed. ret=%d", ret); + } return ret; } srs_info("send onFCUnpublish(NetStream.unpublish.Success) message success."); @@ -2933,7 +2935,9 @@ int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid) if (true) { SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(unpublish_tid); if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send FCUnpublish response message failed. ret=%d", ret); + if (!srs_is_system_control_error(ret) && !srs_is_client_gracefully_close(ret)) { + srs_error("send FCUnpublish response message failed. ret=%d", ret); + } return ret; } srs_info("send FCUnpublish response message success."); @@ -2948,7 +2952,9 @@ int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid) pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Unpublish.Success) message failed. ret=%d", ret); + if (!srs_is_system_control_error(ret) && !srs_is_client_gracefully_close(ret)) { + srs_error("send onStatus(NetStream.Unpublish.Success) message failed. ret=%d", ret); + } return ret; } srs_info("send onStatus(NetStream.Unpublish.Success) message success."); @@ -4234,10 +4240,22 @@ int SrsPlayPacket::get_message_type() int SrsPlayPacket::get_size() { - return SrsAmf0Size::str(command_name) + SrsAmf0Size::number() - + SrsAmf0Size::null() + SrsAmf0Size::str(stream_name) - + SrsAmf0Size::number() + SrsAmf0Size::number() - + SrsAmf0Size::boolean(); + int size = SrsAmf0Size::str(command_name) + SrsAmf0Size::number() + + SrsAmf0Size::null() + SrsAmf0Size::str(stream_name); + + if (start != -2 || duration != -1 || !reset) { + size += SrsAmf0Size::number(); + } + + if (duration != -1 || !reset) { + size += SrsAmf0Size::number(); + } + + if (!reset) { + size += SrsAmf0Size::boolean(); + } + + return size; } int SrsPlayPacket::encode_packet(SrsStream* stream) @@ -4268,19 +4286,19 @@ int SrsPlayPacket::encode_packet(SrsStream* stream) } srs_verbose("encode stream_name success."); - if ((ret = srs_amf0_write_number(stream, start)) != ERROR_SUCCESS) { + if ((start != -2 || duration != -1 || !reset) && (ret = srs_amf0_write_number(stream, start)) != ERROR_SUCCESS) { srs_error("encode start failed. ret=%d", ret); return ret; } srs_verbose("encode start success."); - if ((ret = srs_amf0_write_number(stream, duration)) != ERROR_SUCCESS) { + if ((duration != -1 || !reset) && (ret = srs_amf0_write_number(stream, duration)) != ERROR_SUCCESS) { srs_error("encode duration failed. ret=%d", ret); return ret; } srs_verbose("encode duration success."); - if ((ret = srs_amf0_write_boolean(stream, reset)) != ERROR_SUCCESS) { + if (!reset && (ret = srs_amf0_write_boolean(stream, reset)) != ERROR_SUCCESS) { srs_error("encode reset failed. ret=%d", ret); return ret; } @@ -5111,14 +5129,29 @@ int SrsUserControlPacket::decode(SrsStream* stream) { int ret = ERROR_SUCCESS; - if (!stream->require(6)) { + if (!stream->require(2)) { ret = ERROR_RTMP_MESSAGE_DECODE; srs_error("decode user control failed. ret=%d", ret); return ret; } event_type = stream->read_2bytes(); - event_data = stream->read_4bytes(); + + if (event_type == SrsPCUCFmsEvent0) { + if (!stream->require(1)) { + ret = ERROR_RTMP_MESSAGE_DECODE; + srs_error("decode user control failed. ret=%d", ret); + return ret; + } + event_data = stream->read_1bytes(); + } else { + if (!stream->require(4)) { + ret = ERROR_RTMP_MESSAGE_DECODE; + srs_error("decode user control failed. ret=%d", ret); + return ret; + } + event_data = stream->read_4bytes(); + } if (event_type == SrcPCUCSetBufferLength) { if (!stream->require(4)) { @@ -5148,11 +5181,19 @@ int SrsUserControlPacket::get_message_type() int SrsUserControlPacket::get_size() { - if (event_type == SrcPCUCSetBufferLength) { - return 2 + 4 + 4; + int size = 2; + + if (event_type == SrsPCUCFmsEvent0) { + size += 1; } else { - return 2 + 4; + size += 4; } + + if (event_type == SrcPCUCSetBufferLength) { + size += 4; + } + + return size; } int SrsUserControlPacket::encode_packet(SrsStream* stream) @@ -5166,7 +5207,12 @@ int SrsUserControlPacket::encode_packet(SrsStream* stream) } stream->write_2bytes(event_type); - stream->write_4bytes(event_data); + + if (event_type == SrsPCUCFmsEvent0) { + stream->write_1bytes(event_data); + } else { + stream->write_4bytes(event_data); + } // when event type is set buffer length, // write the extra buffer length. diff --git a/trunk/src/protocol/srs_rtmp_stack.hpp b/trunk/src/protocol/srs_rtmp_stack.hpp index db6d76f46..f2c837fc8 100644 --- a/trunk/src/protocol/srs_rtmp_stack.hpp +++ b/trunk/src/protocol/srs_rtmp_stack.hpp @@ -1991,6 +1991,13 @@ enum SrcPCUCEventType * kMsgPingRequest request. */ SrcPCUCPingResponse = 0x07, + + /** + * for PCUC size=3, the payload is "00 1A 01", + * where we think the event is 0x001a, fms defined msg, + * which has only 1bytes event data. + */ + SrsPCUCFmsEvent0 = 0x1a, }; /** @@ -2019,6 +2026,11 @@ public: * @see: SrcPCUCEventType */ int16_t event_type; + /** + * the event data generally in 4bytes. + * @remark for event type is 0x001a, only 1bytes. + * @see SrsPCUCFmsEvent0 + */ int32_t event_data; /** * 4bytes if event_type is SetBufferLength; otherwise 0.