From b452144fb72c27cba2cd139f7a52d0d69f129540 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 16 Sep 2022 21:54:34 +0800 Subject: [PATCH] GB28181: Remove unused RTSP protocol stack. --- trunk/configure | 2 +- trunk/src/app/srs_app_latest_version.cpp | 10 +- .../src/protocol/srs_protocol_rtsp_stack.cpp | 1083 ----------------- .../src/protocol/srs_protocol_rtsp_stack.hpp | 561 --------- 4 files changed, 6 insertions(+), 1650 deletions(-) delete mode 100644 trunk/src/protocol/srs_protocol_rtsp_stack.cpp delete mode 100644 trunk/src/protocol/srs_protocol_rtsp_stack.hpp diff --git a/trunk/configure b/trunk/configure index 48e19ad15..05fae37f6 100755 --- a/trunk/configure +++ b/trunk/configure @@ -226,7 +226,7 @@ MODULE_DEPENDS=("CORE" "KERNEL") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_protocol_conn" "srs_protocol_rtmp_handshake" "srs_protocol_rtmp_stack" "srs_protocol_utility" "srs_protocol_rtmp_msg_array" "srs_protocol_stream" - "srs_protocol_raw_avc" "srs_protocol_rtsp_stack" "srs_protocol_http_stack" "srs_protocol_kbps" "srs_protocol_json" + "srs_protocol_raw_avc" "srs_protocol_http_stack" "srs_protocol_kbps" "srs_protocol_json" "srs_protocol_format" "srs_protocol_log" "srs_protocol_st" "srs_protocol_http_client" "srs_protocol_http_conn" "srs_protocol_rtmp_conn" "srs_protocol_protobuf") if [[ $SRS_SRT == YES ]]; then diff --git a/trunk/src/app/srs_app_latest_version.cpp b/trunk/src/app/srs_app_latest_version.cpp index 3c5af33e0..f54f18785 100644 --- a/trunk/src/app/srs_app_latest_version.cpp +++ b/trunk/src/app/srs_app_latest_version.cpp @@ -71,7 +71,7 @@ void srs_build_features(stringstream& ss) SRS_CHECK_FEATURE3(!string(source).empty(), "source", source, ss); int nn_vhosts = 0; - bool rtsp = false, forward = false, ingest = false, edge = false, hls = false, dvr = false, flv = false; + bool gb28181 = false, forward = false, ingest = false, edge = false, hls = false, dvr = false, flv = false; bool hooks = false, dash = false, hds = false, exec = false, transcode = false, security = false; bool flv2 = false, oc = false; @@ -80,10 +80,10 @@ void srs_build_features(stringstream& ss) for (int i = 0; i < (int)root->directives.size() && i < 128; i++) { SrsConfDirective* conf = root->at(i); - if (!rtsp && conf->is_stream_caster() && _srs_config->get_stream_caster_enabled(conf)) { + if (!gb28181 && conf->is_stream_caster() && _srs_config->get_stream_caster_enabled(conf)) { string engine = _srs_config->get_stream_caster_engine(conf); - if (engine == "rtsp") { - rtsp = true; + if (engine == "gb28181") { + gb28181 = true; } else if (engine == "flv") { flv2 = true; } @@ -144,7 +144,7 @@ void srs_build_features(stringstream& ss) } SRS_CHECK_FEATURE2(nn_vhosts, "vhosts", ss); - SRS_CHECK_FEATURE(rtsp, ss); + SRS_CHECK_FEATURE(gb28181, ss); SRS_CHECK_FEATURE(flv2, ss); SRS_CHECK_FEATURE(forward, ss); SRS_CHECK_FEATURE(ingest, ss); diff --git a/trunk/src/protocol/srs_protocol_rtsp_stack.cpp b/trunk/src/protocol/srs_protocol_rtsp_stack.cpp deleted file mode 100644 index 9dfa733c8..000000000 --- a/trunk/src/protocol/srs_protocol_rtsp_stack.cpp +++ /dev/null @@ -1,1083 +0,0 @@ -// -// Copyright (c) 2013-2022 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#include - -#include -#include -using namespace std; - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SRS_RTSP_BUFFER 4096 - -// get the status text of code. -string srs_generate_rtsp_status_text(int status) -{ - static std::map _status_map; - if (_status_map.empty()) { - _status_map[SRS_CONSTS_RTSP_Continue] = SRS_CONSTS_RTSP_Continue_str; - _status_map[SRS_CONSTS_RTSP_OK] = SRS_CONSTS_RTSP_OK_str; - _status_map[SRS_CONSTS_RTSP_Created] = SRS_CONSTS_RTSP_Created_str; - _status_map[SRS_CONSTS_RTSP_LowOnStorageSpace] = SRS_CONSTS_RTSP_LowOnStorageSpace_str; - _status_map[SRS_CONSTS_RTSP_MultipleChoices] = SRS_CONSTS_RTSP_MultipleChoices_str; - _status_map[SRS_CONSTS_RTSP_MovedPermanently] = SRS_CONSTS_RTSP_MovedPermanently_str; - _status_map[SRS_CONSTS_RTSP_MovedTemporarily] = SRS_CONSTS_RTSP_MovedTemporarily_str; - _status_map[SRS_CONSTS_RTSP_SeeOther] = SRS_CONSTS_RTSP_SeeOther_str; - _status_map[SRS_CONSTS_RTSP_NotModified] = SRS_CONSTS_RTSP_NotModified_str; - _status_map[SRS_CONSTS_RTSP_UseProxy] = SRS_CONSTS_RTSP_UseProxy_str; - _status_map[SRS_CONSTS_RTSP_BadRequest] = SRS_CONSTS_RTSP_BadRequest_str; - _status_map[SRS_CONSTS_RTSP_Unauthorized] = SRS_CONSTS_RTSP_Unauthorized_str; - _status_map[SRS_CONSTS_RTSP_PaymentRequired] = SRS_CONSTS_RTSP_PaymentRequired_str; - _status_map[SRS_CONSTS_RTSP_Forbidden] = SRS_CONSTS_RTSP_Forbidden_str; - _status_map[SRS_CONSTS_RTSP_NotFound] = SRS_CONSTS_RTSP_NotFound_str; - _status_map[SRS_CONSTS_RTSP_MethodNotAllowed] = SRS_CONSTS_RTSP_MethodNotAllowed_str; - _status_map[SRS_CONSTS_RTSP_NotAcceptable] = SRS_CONSTS_RTSP_NotAcceptable_str; - _status_map[SRS_CONSTS_RTSP_ProxyAuthenticationRequired] = SRS_CONSTS_RTSP_ProxyAuthenticationRequired_str; - _status_map[SRS_CONSTS_RTSP_RequestTimeout] = SRS_CONSTS_RTSP_RequestTimeout_str; - _status_map[SRS_CONSTS_RTSP_Gone] = SRS_CONSTS_RTSP_Gone_str; - _status_map[SRS_CONSTS_RTSP_LengthRequired] = SRS_CONSTS_RTSP_LengthRequired_str; - _status_map[SRS_CONSTS_RTSP_PreconditionFailed] = SRS_CONSTS_RTSP_PreconditionFailed_str; - _status_map[SRS_CONSTS_RTSP_RequestEntityTooLarge] = SRS_CONSTS_RTSP_RequestEntityTooLarge_str; - _status_map[SRS_CONSTS_RTSP_RequestURITooLarge] = SRS_CONSTS_RTSP_RequestURITooLarge_str; - _status_map[SRS_CONSTS_RTSP_UnsupportedMediaType] = SRS_CONSTS_RTSP_UnsupportedMediaType_str; - _status_map[SRS_CONSTS_RTSP_ParameterNotUnderstood] = SRS_CONSTS_RTSP_ParameterNotUnderstood_str; - _status_map[SRS_CONSTS_RTSP_ConferenceNotFound] = SRS_CONSTS_RTSP_ConferenceNotFound_str; - _status_map[SRS_CONSTS_RTSP_NotEnoughBandwidth] = SRS_CONSTS_RTSP_NotEnoughBandwidth_str; - _status_map[SRS_CONSTS_RTSP_SessionNotFound] = SRS_CONSTS_RTSP_SessionNotFound_str; - _status_map[SRS_CONSTS_RTSP_MethodNotValidInThisState] = SRS_CONSTS_RTSP_MethodNotValidInThisState_str; - _status_map[SRS_CONSTS_RTSP_HeaderFieldNotValidForResource] = SRS_CONSTS_RTSP_HeaderFieldNotValidForResource_str; - _status_map[SRS_CONSTS_RTSP_InvalidRange] = SRS_CONSTS_RTSP_InvalidRange_str; - _status_map[SRS_CONSTS_RTSP_ParameterIsReadOnly] = SRS_CONSTS_RTSP_ParameterIsReadOnly_str; - _status_map[SRS_CONSTS_RTSP_AggregateOperationNotAllowed] = SRS_CONSTS_RTSP_AggregateOperationNotAllowed_str; - _status_map[SRS_CONSTS_RTSP_OnlyAggregateOperationAllowed] = SRS_CONSTS_RTSP_OnlyAggregateOperationAllowed_str; - _status_map[SRS_CONSTS_RTSP_UnsupportedTransport] = SRS_CONSTS_RTSP_UnsupportedTransport_str; - _status_map[SRS_CONSTS_RTSP_DestinationUnreachable] = SRS_CONSTS_RTSP_DestinationUnreachable_str; - _status_map[SRS_CONSTS_RTSP_InternalServerError] = SRS_CONSTS_RTSP_InternalServerError_str; - _status_map[SRS_CONSTS_RTSP_NotImplemented] = SRS_CONSTS_RTSP_NotImplemented_str; - _status_map[SRS_CONSTS_RTSP_BadGateway] = SRS_CONSTS_RTSP_BadGateway_str; - _status_map[SRS_CONSTS_RTSP_ServiceUnavailable] = SRS_CONSTS_RTSP_ServiceUnavailable_str; - _status_map[SRS_CONSTS_RTSP_GatewayTimeout] = SRS_CONSTS_RTSP_GatewayTimeout_str; - _status_map[SRS_CONSTS_RTSP_RTSPVersionNotSupported] = SRS_CONSTS_RTSP_RTSPVersionNotSupported_str; - _status_map[SRS_CONSTS_RTSP_OptionNotSupported] = SRS_CONSTS_RTSP_OptionNotSupported_str; - } - - std::string status_text; - if (_status_map.find(status) == _status_map.end()) { - status_text = "Status Unknown"; - } else { - status_text = _status_map[status]; - } - - return status_text; -} - -std::string srs_generate_rtsp_method_str(SrsRtspMethod method) -{ - switch (method) { - case SrsRtspMethodDescribe: return SRS_METHOD_DESCRIBE; - case SrsRtspMethodAnnounce: return SRS_METHOD_ANNOUNCE; - case SrsRtspMethodGetParameter: return SRS_METHOD_GET_PARAMETER; - case SrsRtspMethodOptions: return SRS_METHOD_OPTIONS; - case SrsRtspMethodPause: return SRS_METHOD_PAUSE; - case SrsRtspMethodPlay: return SRS_METHOD_PLAY; - case SrsRtspMethodRecord: return SRS_METHOD_RECORD; - case SrsRtspMethodRedirect: return SRS_METHOD_REDIRECT; - case SrsRtspMethodSetup: return SRS_METHOD_SETUP; - case SrsRtspMethodSetParameter: return SRS_METHOD_SET_PARAMETER; - case SrsRtspMethodTeardown: return SRS_METHOD_TEARDOWN; - default: return "Unknown"; - } -} - -SrsRtspPacket::SrsRtspPacket() -{ - version = 2; - padding = 0; - extension = 0; - csrc_count = 0; - marker = 1; - - payload_type = 0; - sequence_number = 0; - timestamp = 0; - ssrc = 0; - - payload = new SrsSimpleStream(); - audio = new SrsAudioFrame(); - chunked = false; - completed = false; -} - -SrsRtspPacket::~SrsRtspPacket() -{ - srs_freep(payload); - srs_freep(audio); -} - -void SrsRtspPacket::copy(SrsRtspPacket* src) -{ - version = src->version; - padding = src->padding; - extension = src->extension; - csrc_count = src->csrc_count; - marker = src->marker; - payload_type = src->payload_type; - sequence_number = src->sequence_number; - timestamp = src->timestamp; - ssrc = src->ssrc; - - chunked = src->chunked; - completed = src->completed; - - srs_freep(audio); - audio = new SrsAudioFrame(); -} - -void SrsRtspPacket::reap(SrsRtspPacket* src) -{ - copy(src); - - srs_freep(payload); - payload = src->payload; - src->payload = NULL; - - srs_freep(audio); - audio = src->audio; - src->audio = NULL; -} - -srs_error_t SrsRtspPacket::decode(SrsBuffer* stream) -{ - srs_error_t err = srs_success; - - // 12bytes header - if (!stream->require(12)) { - return srs_error_new(ERROR_RTP_HEADER_CORRUPT, "requires 12 only %d bytes", stream->left()); - } - - int8_t vv = stream->read_1bytes(); - version = (vv >> 6) & 0x03; - padding = (vv >> 5) & 0x01; - extension = (vv >> 4) & 0x01; - csrc_count = vv & 0x0f; - - int8_t mv = stream->read_1bytes(); - marker = (mv >> 7) & 0x01; - payload_type = mv & 0x7f; - - sequence_number = stream->read_2bytes(); - timestamp = stream->read_4bytes(); - ssrc = stream->read_4bytes(); - - // TODO: FIXME: check sequence number. - - // video codec. - if (payload_type == 96) { - return decode_96(stream); - } else if (payload_type == 97) { - return decode_97(stream); - } - - return err; -} - -srs_error_t SrsRtspPacket::decode_97(SrsBuffer* stream) -{ - srs_error_t err = srs_success; - - // atleast 2bytes content. - if (!stream->require(2)) { - return srs_error_new(ERROR_RTP_TYPE97_CORRUPT, "requires 2 only %d bytes", stream->left()); - } - - int8_t hasv = stream->read_1bytes(); - int8_t lasv = stream->read_1bytes(); - uint16_t au_size = ((hasv << 5) & 0xE0) | ((lasv >> 3) & 0x1f); - - if (!stream->require(au_size)) { - return srs_error_new(ERROR_RTP_TYPE97_CORRUPT, "requires %d only %d bytes", au_size, stream->left()); - } - - int required_size = 0; - - // append left bytes to payload. - payload->append(stream->data() + stream->pos() + au_size, stream->size() - stream->pos() - au_size); - char* p = payload->bytes(); - - for (int i = 0; i < au_size; i += 2) { - hasv = stream->read_1bytes(); - lasv = stream->read_1bytes(); - - uint16_t sample_size = ((hasv << 5) & 0xE0) | ((lasv >> 3) & 0x1f); - // TODO: FIXME: finger out how to parse the size of sample. - if (sample_size < 0x100 && stream->require(required_size + sample_size + 0x100)) { - sample_size = sample_size | 0x100; - } - - char* sample = p + required_size; - required_size += sample_size; - - if (!stream->require(required_size)) { - return srs_error_new(ERROR_RTP_TYPE97_CORRUPT, "requires %d only %d bytes", required_size, stream->left()); - } - - if ((err = audio->add_sample(sample, sample_size)) != srs_success) { - srs_freep(err); - return srs_error_wrap(err, "add sample"); - } - } - - // parsed ok. - completed = true; - - return err; -} - -srs_error_t SrsRtspPacket::decode_96(SrsBuffer* stream) -{ - srs_error_t err = srs_success; - - // atleast 2bytes content. - if (!stream->require(2)) { - return srs_error_new(ERROR_RTP_TYPE96_CORRUPT, "requires 2 only %d bytes", stream->left()); - } - - // frame type - // 0... .... reserverd - // .11. .... NALU[0]&0x60 - // ...1 11.. FU indicator - // .... ..00 reserverd - int8_t ftv = stream->read_1bytes(); - int8_t nalu_0x60 = ftv & 0x60; - int8_t fu_indicator = ftv & 0x1c; - - // nri, whatever - // 10.. .... first chunk. - // 00.. .... continous chunk. - // 01.. .... last chunk. - // ...1 1111 NALU[0]&0x1f - int8_t nriv = stream->read_1bytes(); - bool first_chunk = (nriv & 0xC0) == 0x80; - bool last_chunk = (nriv & 0xC0) == 0x40; - bool contious_chunk = (nriv & 0xC0) == 0x00; - int8_t nalu_0x1f = nriv & 0x1f; - - // chunked, generate the first byte NALU. - if (fu_indicator == 0x1c && (first_chunk || last_chunk || contious_chunk)) { - chunked = true; - completed = last_chunk; - - // generate and append the first byte NALU. - if (first_chunk) { - int8_t nalu_byte0 = nalu_0x60 | nalu_0x1f; - payload->append((char*)&nalu_byte0, 1); - } - - payload->append(stream->data() + stream->pos(), stream->size() - stream->pos()); - return err; - } - - // no chunked, append to payload. - stream->skip(-2); - payload->append(stream->data() + stream->pos(), stream->size() - stream->pos()); - completed = true; - - return err; -} - -SrsRtspSdp::SrsRtspSdp() -{ - state = SrsRtspSdpStateOthers; -} - -SrsRtspSdp::~SrsRtspSdp() -{ -} - -srs_error_t SrsRtspSdp::parse(string token) -{ - srs_error_t err = srs_success; - - if (token.empty()) { - // ignore empty token - return err; - } - - size_t pos = string::npos; - - char* start = (char*)token.data(); - char* end = start + (int)token.length(); - char* p = start; - - // key, first 2bytes. - // v=0 - // o=- 0 0 IN IP4 127.0.0.1 - // s=No Name - // c=IN IP4 192.168.43.23 - // t=0 0 - // a=tool:libavformat 53.9.0 - // m=video 0 RTP/AVP 96 - // b=AS:850 - // a=rtpmap:96 H264/90000 - // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAKKzRwFAFu/8ALQAiEAAAAwAQAAADAwjxgxHg,aOmrLIs= - // a=control:streamid=0 - // m=audio 0 RTP/AVP 97 - // b=AS:49 - // a=rtpmap:97 MPEG4-GENERIC/44100/2 - // a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=139056E5A0 - // a=control:streamid=1 - char key = p[0]; - p += 2; - - // left bytes as attr string. - std::string attr_str; - if (end - p) { - attr_str.append(p, end - p); - } - - // parse the attributes from left bytes. - std::vector attrs; - while (p < end) { - // parse an attribute, split by SP. - char* pa = p; - for (; p < end && p[0] != SRS_RTSP_SP; p++) { - } - std::string attr; - if (p > pa) { - attr.append(pa, p - pa); - attrs.push_back(attr); - } - p++; - } - - // parse the first attr as desc, update the first elem for desc. - // for example, the value can be "tool", "AS", "rtpmap", "fmtp", "control" - std::string desc_key; - if (attrs.size() > 0) { - std::string attr = attrs.at(0); - if ((pos = attr.find(":")) != string::npos) { - desc_key = attr.substr(0, pos); - attr = attr.substr(pos + 1); - attr_str = attr_str.substr(pos + 1); - attrs[0] = attr; - } else { - desc_key = attr; - } - } - - // interpret the attribute according by key. - switch (key) { - case 'v': version = attr_str; break; - case 'o': - owner_username = (attrs.size() > 0)? attrs[0]:""; - owner_session_id = (attrs.size() > 1)? attrs[1]:""; - owner_session_version = (attrs.size() > 2)? attrs[2]:""; - owner_network_type = (attrs.size() > 3)? attrs[3]:""; - owner_address_type = (attrs.size() > 4)? attrs[4]:""; - owner_address = (attrs.size() > 5)? attrs[5]:""; - break; - case 's': session_name = attr_str; break; - case 'c': - connection_network_type = (attrs.size() > 0)? attrs[0]:""; - connection_address_type = (attrs.size() > 0)? attrs[0]:""; - connection_address = (attrs.size() > 0)? attrs[0]:""; - break; - case 'a': - if (desc_key == "tool") { - tool = attr_str; - } else if (desc_key == "rtpmap") { - if (state == SrsRtspSdpStateVideo) { - video_codec = (attrs.size() > 1)? attrs[1]:""; - if ((pos = video_codec.find("/")) != string::npos) { - video_sample_rate = video_codec.substr(pos + 1); - video_codec = video_codec.substr(0, pos); - } - } else if (state == SrsRtspSdpStateAudio) { - audio_codec = (attrs.size() > 1)? attrs[1]:""; - if ((pos = audio_codec.find("/")) != string::npos) { - audio_sample_rate = audio_codec.substr(pos + 1); - audio_codec = audio_codec.substr(0, pos); - } - if ((pos = audio_sample_rate.find("/")) != string::npos) { - audio_channel = audio_sample_rate.substr(pos + 1); - audio_sample_rate = audio_sample_rate.substr(0, pos); - } - } - } else if (desc_key == "fmtp") { - for (int i = 1; i < (int)attrs.size(); i++) { - std::string attr = attrs.at(i); - if ((err = parse_fmtp_attribute(attr)) != srs_success) { - return srs_error_wrap(err, "parse fmtp attr=%s", attr.c_str()); - } - } - } else if (desc_key == "control") { - for (int i = 0; i < (int)attrs.size(); i++) { - std::string attr = attrs.at(i); - if ((err = parse_control_attribute(attr)) != srs_success) { - return srs_error_wrap(err, "parse control attr=%s", attr.c_str()); - } - } - } - break; - case 'm': - if (desc_key == "video") { - state = SrsRtspSdpStateVideo; - video_port = (attrs.size() > 1)? attrs[1]:""; - video_protocol = (attrs.size() > 2)? attrs[2]:""; - video_transport_format = (attrs.size() > 3)? attrs[3]:""; - } else if (desc_key == "audio") { - state = SrsRtspSdpStateAudio; - audio_port = (attrs.size() > 1)? attrs[1]:""; - audio_protocol = (attrs.size() > 2)? attrs[2]:""; - audio_transport_format = (attrs.size() > 3)? attrs[3]:""; - } - break; - case 'b': - if (desc_key == "AS") { - if (state == SrsRtspSdpStateVideo) { - video_bandwidth_kbps = (attrs.size() > 0)? attrs[0]:""; - } else if (state == SrsRtspSdpStateAudio) { - audio_bandwidth_kbps = (attrs.size() > 0)? attrs[0]:""; - } - } - break; - case 't': - default: break; - } - - return err; -} - -srs_error_t SrsRtspSdp::parse_fmtp_attribute(string attr) -{ - srs_error_t err = srs_success; - - size_t pos = string::npos; - std::string token = attr; - - while (!token.empty()) { - std::string item = token; - if ((pos = item.find(";")) != string::npos) { - item = token.substr(0, pos); - token = token.substr(pos + 1); - } else { - token = ""; - } - - std::string item_key = item, item_value; - if ((pos = item.find("=")) != string::npos) { - item_key = item.substr(0, pos); - item_value = item.substr(pos + 1); - } - - if (state == SrsRtspSdpStateVideo) { - if (item_key == "packetization-mode") { - video_packetization_mode = item_value; - } else if (item_key == "sprop-parameter-sets") { - video_sps = item_value; - if ((pos = video_sps.find(",")) != string::npos) { - video_pps = video_sps.substr(pos + 1); - video_sps = video_sps.substr(0, pos); - } - // decode the sps/pps by base64 - video_sps = base64_decode(video_sps); - video_pps = base64_decode(video_pps); - } - } else if (state == SrsRtspSdpStateAudio) { - if (item_key == "profile-level-id") { - audio_profile_level_id = item_value; - } else if (item_key == "mode") { - audio_mode = item_value; - } else if (item_key == "sizelength") { - audio_size_length = item_value; - } else if (item_key == "indexlength") { - audio_index_length = item_value; - } else if (item_key == "indexdeltalength") { - audio_index_delta_length = item_value; - } else if (item_key == "config") { - if (item_value.length() <= 0) { - return srs_error_new(ERROR_RTSP_AUDIO_CONFIG, "audio config"); - } - - char* tmp_sh = new char[item_value.length()]; - SrsAutoFreeA(char, tmp_sh); - - int nb_tmp_sh = srs_hex_to_data((uint8_t*)tmp_sh, item_value.c_str(), item_value.length()); - if (nb_tmp_sh <= 0) { - return srs_error_new(ERROR_RTSP_AUDIO_CONFIG, "audio config"); - } - - audio_sh.append(tmp_sh, nb_tmp_sh); - } - } - } - - return err; -} - -srs_error_t SrsRtspSdp::parse_control_attribute(string attr) -{ - srs_error_t err = srs_success; - - size_t pos = string::npos; - std::string token = attr; - - while (!token.empty()) { - std::string item = token; - if ((pos = item.find(";")) != string::npos) { - item = token.substr(0, pos); - token = token.substr(pos + 1); - } else { - token = ""; - } - - std::string item_key = item, item_value; - if ((pos = item.find("=")) != string::npos) { - item_key = item.substr(0, pos); - item_value = item.substr(pos + 1); - } - - if (state == SrsRtspSdpStateVideo) { - if (item_key == "streamid") { - video_stream_id = item_value; - } - } else if (state == SrsRtspSdpStateAudio) { - if (item_key == "streamid") { - audio_stream_id = item_value; - } - } - } - - return err; -} - -string SrsRtspSdp::base64_decode(string cipher) -{ - if (cipher.empty()) { - return ""; - } - - string plaintext; - srs_error_t err = srs_av_base64_decode(cipher, plaintext); - srs_freep(err); - - return plaintext; -} - -SrsRtspTransport::SrsRtspTransport() -{ - client_port_min = 0; - client_port_max = 0; -} - -SrsRtspTransport::~SrsRtspTransport() -{ -} - -srs_error_t SrsRtspTransport::parse(string attr) -{ - srs_error_t err = srs_success; - - size_t pos = string::npos; - std::string token = attr; - - while (!token.empty()) { - std::string item = token; - if ((pos = item.find(";")) != string::npos) { - item = token.substr(0, pos); - token = token.substr(pos + 1); - } else { - token = ""; - } - - std::string item_key = item, item_value; - if ((pos = item.find("=")) != string::npos) { - item_key = item.substr(0, pos); - item_value = item.substr(pos + 1); - } - - if (transport.empty()) { - transport = item_key; - if ((pos = transport.find("/")) != string::npos) { - profile = transport.substr(pos + 1); - transport = transport.substr(0, pos); - } - if ((pos = profile.find("/")) != string::npos) { - lower_transport = profile.substr(pos + 1); - profile = profile.substr(0, pos); - } - } - - if (item_key == "unicast" || item_key == "multicast") { - cast_type = item_key; - } else if (item_key == "mode") { - mode = item_value; - } else if (item_key == "client_port") { - std::string sport = item_value; - std::string eport = item_value; - if ((pos = eport.find("-")) != string::npos) { - sport = eport.substr(0, pos); - eport = eport.substr(pos + 1); - } - client_port_min = ::atoi(sport.c_str()); - client_port_max = ::atoi(eport.c_str()); - } - } - - return err; -} - -SrsRtspRequest::SrsRtspRequest() -{ - seq = 0; - content_length = 0; - stream_id = 0; - sdp = NULL; - transport = NULL; -} - -SrsRtspRequest::~SrsRtspRequest() -{ - srs_freep(sdp); - srs_freep(transport); -} - -bool SrsRtspRequest::is_options() -{ - return method == SRS_METHOD_OPTIONS; -} - -bool SrsRtspRequest::is_announce() -{ - return method == SRS_METHOD_ANNOUNCE; -} - -bool SrsRtspRequest::is_setup() -{ - return method == SRS_METHOD_SETUP; -} - -bool SrsRtspRequest::is_record() -{ - return method == SRS_METHOD_RECORD; -} - -SrsRtspResponse::SrsRtspResponse(int cseq) -{ - seq = cseq; - status = SRS_CONSTS_RTSP_OK; -} - -SrsRtspResponse::~SrsRtspResponse() -{ -} - -srs_error_t SrsRtspResponse::encode(stringstream& ss) -{ - srs_error_t err = srs_success; - - // status line - ss << SRS_RTSP_VERSION << SRS_RTSP_SP - << status << SRS_RTSP_SP - << srs_generate_rtsp_status_text(status) << SRS_RTSP_CRLF; - - // cseq - ss << SRS_RTSP_TOKEN_CSEQ << ":" << SRS_RTSP_SP << seq << SRS_RTSP_CRLF; - - // others. - ss << "Cache-Control: no-store" << SRS_RTSP_CRLF - << "Pragma: no-cache" << SRS_RTSP_CRLF - << "Server: " << RTMP_SIG_SRS_SERVER << SRS_RTSP_CRLF; - - // session if specified. - if (!session.empty()) { - ss << SRS_RTSP_TOKEN_SESSION << ":" << session << SRS_RTSP_CRLF; - } - - if ((err = encode_header(ss)) != srs_success) { - return srs_error_wrap(err, "encode header"); - }; - - // header EOF. - ss << SRS_RTSP_CRLF; - - return err; -} - -srs_error_t SrsRtspResponse::encode_header(std::stringstream& ss) -{ - return srs_success; -} - -SrsRtspOptionsResponse::SrsRtspOptionsResponse(int cseq) : SrsRtspResponse(cseq) -{ - methods = (SrsRtspMethod)(SrsRtspMethodDescribe | SrsRtspMethodOptions - | SrsRtspMethodPause | SrsRtspMethodPlay | SrsRtspMethodSetup | SrsRtspMethodTeardown - | SrsRtspMethodAnnounce | SrsRtspMethodRecord); -} - -SrsRtspOptionsResponse::~SrsRtspOptionsResponse() -{ -} - -srs_error_t SrsRtspOptionsResponse::encode_header(stringstream& ss) -{ - SrsRtspMethod rtsp_methods[] = { - SrsRtspMethodDescribe, - SrsRtspMethodAnnounce, - SrsRtspMethodGetParameter, - SrsRtspMethodOptions, - SrsRtspMethodPause, - SrsRtspMethodPlay, - SrsRtspMethodRecord, - SrsRtspMethodRedirect, - SrsRtspMethodSetup, - SrsRtspMethodSetParameter, - SrsRtspMethodTeardown, - }; - - ss << SRS_RTSP_TOKEN_PUBLIC << ":" << SRS_RTSP_SP; - - bool appended = false; - int nb_methods = (int)(sizeof(rtsp_methods) / sizeof(SrsRtspMethod)); - for (int i = 0; i < nb_methods; i++) { - SrsRtspMethod method = rtsp_methods[i]; - if (((int)methods & (int)method) != (int)method) { - continue; - } - - if (appended) { - ss << ", "; - } - ss << srs_generate_rtsp_method_str(method); - appended = true; - } - ss << SRS_RTSP_CRLF; - - return srs_success; -} - -SrsRtspSetupResponse::SrsRtspSetupResponse(int seq) : SrsRtspResponse(seq) -{ - local_port_min = 0; - local_port_max = 0; - - client_port_min = 0; - client_port_max = 0; -} - -SrsRtspSetupResponse::~SrsRtspSetupResponse() -{ -} - -srs_error_t SrsRtspSetupResponse::encode_header(stringstream& ss) -{ - ss << SRS_RTSP_TOKEN_SESSION << ":" << SRS_RTSP_SP << session << SRS_RTSP_CRLF; - ss << SRS_RTSP_TOKEN_TRANSPORT << ":" << SRS_RTSP_SP - << "RTP/AVP;unicast;client_port=" << client_port_min << "-" << client_port_max << ";" - << "server_port=" << local_port_min << "-" << local_port_max - << SRS_RTSP_CRLF; - return srs_success; -} - -SrsRtspStack::SrsRtspStack(ISrsProtocolReadWriter* s) -{ - buf = new SrsSimpleStream(); - skt = s; -} - -SrsRtspStack::~SrsRtspStack() -{ - srs_freep(buf); -} - -srs_error_t SrsRtspStack::recv_message(SrsRtspRequest** preq) -{ - srs_error_t err = srs_success; - - SrsRtspRequest* req = new SrsRtspRequest(); - if ((err = do_recv_message(req)) != srs_success) { - srs_freep(req); - return srs_error_wrap(err, "recv message"); - } - - *preq = req; - - return err; -} - -srs_error_t SrsRtspStack::send_message(SrsRtspResponse* res) -{ - srs_error_t err = srs_success; - - std::stringstream ss; - // encode the message to string. - res->encode(ss); - - std::string str = ss.str(); - srs_assert(!str.empty()); - - if ((err = skt->write((char*)str.c_str(), (int)str.length(), NULL)) != srs_success) { - return srs_error_wrap(err, "write message"); - } - - return err; -} - -srs_error_t SrsRtspStack::do_recv_message(SrsRtspRequest* req) -{ - srs_error_t err = srs_success; - - // parse request line. - if ((err = recv_token_normal(req->method)) != srs_success) { - return srs_error_wrap(err, "method"); - } - - if ((err = recv_token_normal(req->uri)) != srs_success) { - return srs_error_wrap(err, "uri"); - } - - if ((err = recv_token_eof(req->version)) != srs_success) { - return srs_error_wrap(err, "version"); - } - - // parse headers. - for (;;) { - // parse the header name - std::string token; - if ((err = recv_token_normal(token)) != srs_success) { - if (srs_error_code(err) == ERROR_RTSP_REQUEST_HEADER_EOF) { - srs_error_reset(err); - break; - } - return srs_error_wrap(err, "recv token"); - } - - // parse the header value according by header name - if (token == SRS_RTSP_TOKEN_CSEQ) { - std::string seq; - if ((err = recv_token_eof(seq)) != srs_success) { - return srs_error_wrap(err, "seq"); - } - req->seq = ::atoll(seq.c_str()); - } else if (token == SRS_RTSP_TOKEN_CONTENT_TYPE) { - std::string ct; - if ((err = recv_token_eof(ct)) != srs_success) { - return srs_error_wrap(err, "ct"); - } - req->content_type = ct; - } else if (token == SRS_RTSP_TOKEN_CONTENT_LENGTH) { - std::string cl; - if ((err = recv_token_eof(cl)) != srs_success) { - return srs_error_wrap(err, "cl"); - } - req->content_length = ::atoll(cl.c_str()); - } else if (token == SRS_RTSP_TOKEN_TRANSPORT) { - std::string transport; - if ((err = recv_token_eof(transport)) != srs_success) { - return srs_error_wrap(err, "transport"); - } - if (!req->transport) { - req->transport = new SrsRtspTransport(); - } - if ((err = req->transport->parse(transport)) != srs_success) { - return srs_error_wrap(err, "parse transport=%s", transport.c_str()); - } - } else if (token == SRS_RTSP_TOKEN_SESSION) { - if ((err = recv_token_eof(req->session)) != srs_success) { - return srs_error_wrap(err, "session"); - } - } else { - // unknown header name, parse util EOF. - SrsRtspTokenState state = SrsRtspTokenStateNormal; - while (state == SrsRtspTokenStateNormal) { - std::string value; - if ((err = recv_token(value, state)) != srs_success) { - return srs_error_wrap(err, "state"); - } - srs_trace("rtsp: ignore header %s=%s", token.c_str(), value.c_str()); - } - } - } - - // for setup, parse the stream id from uri. - if (req->is_setup()) { - size_t pos = string::npos; - std::string stream_id = srs_path_basename(req->uri); - if ((pos = stream_id.find("=")) != string::npos) { - stream_id = stream_id.substr(pos + 1); - } - req->stream_id = ::atoi(stream_id.c_str()); - srs_info("rtsp: setup stream id=%d", req->stream_id); - } - - // parse rdp body. - long consumed = 0; - while (consumed < req->content_length) { - if (!req->sdp) { - req->sdp = new SrsRtspSdp(); - } - - int nb_token = 0; - std::string token; - if ((err = recv_token_util_eof(token, &nb_token)) != srs_success) { - return srs_error_wrap(err, "recv token"); - } - consumed += nb_token; - - if ((err = req->sdp->parse(token)) != srs_success) { - return srs_error_wrap(err, "parse token"); - } - } - - return err; -} - -srs_error_t SrsRtspStack::recv_token_normal(std::string& token) -{ - srs_error_t err = srs_success; - - SrsRtspTokenState state; - - if ((err = recv_token(token, state)) != srs_success) { - if (srs_error_code(err) == ERROR_RTSP_REQUEST_HEADER_EOF) { - return srs_error_wrap(err, "EOF"); - } - return srs_error_wrap(err, "recv token"); - } - - if (state != SrsRtspTokenStateNormal) { - return srs_error_new(ERROR_RTSP_TOKEN_NOT_NORMAL, "invalid state=%d", state); - } - - return err; -} - -srs_error_t SrsRtspStack::recv_token_eof(std::string& token) -{ - srs_error_t err = srs_success; - - SrsRtspTokenState state; - - if ((err = recv_token(token, state)) != srs_success) { - if (srs_error_code(err) == ERROR_RTSP_REQUEST_HEADER_EOF) { - return srs_error_wrap(err, "EOF"); - } - return srs_error_wrap(err, "recv token"); - } - - if (state != SrsRtspTokenStateEOF) { - return srs_error_new(ERROR_RTSP_TOKEN_NOT_NORMAL, "invalid state=%d", state); - } - - return err; -} - -srs_error_t SrsRtspStack::recv_token_util_eof(std::string& token, int* pconsumed) -{ - srs_error_t err = srs_success; - - SrsRtspTokenState state; - - // use 0x00 as ignore the normal token flag. - if ((err = recv_token(token, state, 0x00, pconsumed)) != srs_success) { - if (srs_error_code(err) == ERROR_RTSP_REQUEST_HEADER_EOF) { - return srs_error_wrap(err, "EOF"); - } - return srs_error_wrap(err, "recv token"); - } - - if (state != SrsRtspTokenStateEOF) { - return srs_error_new(ERROR_RTSP_TOKEN_NOT_NORMAL, "invalid state=%d", state); - } - - return err; -} - -srs_error_t SrsRtspStack::recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch, int* pconsumed) -{ - srs_error_t err = srs_success; - - // whatever, default to error state. - state = SrsRtspTokenStateError; - - // when buffer is empty, append bytes first. - bool append_bytes = buf->length() == 0; - - // parse util token. - for (;;) { - // append bytes if required. - if (append_bytes) { - append_bytes = false; - - char buffer[SRS_RTSP_BUFFER]; - ssize_t nb_read = 0; - if ((err = skt->read(buffer, SRS_RTSP_BUFFER, &nb_read)) != srs_success) { - return srs_error_wrap(err, "recv data"); - } - - buf->append(buffer, (int)nb_read); - } - - // parse one by one. - char* start = buf->bytes(); - char* end = start + buf->length(); - char* p = start; - - // find util SP/CR/LF, max 2 EOF, to finger out the EOF of message. - for (; p < end && p[0] != normal_ch && p[0] != SRS_RTSP_CR && p[0] != SRS_RTSP_LF; p++) { - } - - // matched. - if (p < end) { - // finger out the state. - if (p[0] == normal_ch) { - state = SrsRtspTokenStateNormal; - } else { - state = SrsRtspTokenStateEOF; - } - - // got the token. - int nb_token = (int)(p - start); - // trim last ':' character. - if (nb_token && p[-1] == ':') { - nb_token--; - } - if (nb_token) { - token.append(start, nb_token); - } else { - err = srs_error_new(ERROR_RTSP_REQUEST_HEADER_EOF, "EOF"); - } - - // ignore SP/CR/LF - for (int i = 0; i < 2 && p < end && (p[0] == normal_ch || p[0] == SRS_RTSP_CR || p[0] == SRS_RTSP_LF); p++, i++) { - } - - // consume the token bytes. - srs_assert(p - start); - buf->erase((int)(p - start)); - if (pconsumed) { - *pconsumed = (int)(p - start); - } - break; - } - - // append more and parse again. - append_bytes = true; - } - - return err; -} - diff --git a/trunk/src/protocol/srs_protocol_rtsp_stack.hpp b/trunk/src/protocol/srs_protocol_rtsp_stack.hpp deleted file mode 100644 index c2a023dbc..000000000 --- a/trunk/src/protocol/srs_protocol_rtsp_stack.hpp +++ /dev/null @@ -1,561 +0,0 @@ -// -// Copyright (c) 2013-2022 The SRS Authors -// -// SPDX-License-Identifier: MIT or MulanPSL-2.0 -// - -#ifndef SRS_PROTOCOL_RTSP_HPP -#define SRS_PROTOCOL_RTSP_HPP - -#include - -#include -#include - -#include - -class SrsBuffer; -class SrsSimpleStream; -class SrsAudioFrame; -class ISrsProtocolReadWriter; - -// From rtsp specification -// CR = -#define SRS_RTSP_CR SRS_CONSTS_CR // 0x0D -// LF = -#define SRS_RTSP_LF SRS_CONSTS_LF // 0x0A -// SP = -#define SRS_RTSP_SP ' ' // 0x20 - -// 4 RTSP Message, @see rfc2326-1998-rtsp.pdf, page 37 -// Lines are terminated by CRLF, but -// receivers should be prepared to also interpret CR and LF by -// themselves as line terminators. -#define SRS_RTSP_CRLF "\r\n" // 0x0D0A -#define SRS_RTSP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A - -// RTSP token -#define SRS_RTSP_TOKEN_CSEQ "CSeq" -#define SRS_RTSP_TOKEN_PUBLIC "Public" -#define SRS_RTSP_TOKEN_CONTENT_TYPE "Content-Type" -#define SRS_RTSP_TOKEN_CONTENT_LENGTH "Content-Length" -#define SRS_RTSP_TOKEN_TRANSPORT "Transport" -#define SRS_RTSP_TOKEN_SESSION "Session" - -// RTSP methods -#define SRS_METHOD_OPTIONS "OPTIONS" -#define SRS_METHOD_DESCRIBE "DESCRIBE" -#define SRS_METHOD_ANNOUNCE "ANNOUNCE" -#define SRS_METHOD_SETUP "SETUP" -#define SRS_METHOD_PLAY "PLAY" -#define SRS_METHOD_PAUSE "PAUSE" -#define SRS_METHOD_TEARDOWN "TEARDOWN" -#define SRS_METHOD_GET_PARAMETER "GET_PARAMETER" -#define SRS_METHOD_SET_PARAMETER "SET_PARAMETER" -#define SRS_METHOD_REDIRECT "REDIRECT" -#define SRS_METHOD_RECORD "RECORD" -// Embedded (Interleaved) Binary Data - -// RTSP-Version -#define SRS_RTSP_VERSION "RTSP/1.0" - -// The rtsp sdp parse state. -enum SrsRtspSdpState -{ - // Other sdp properties. - SrsRtspSdpStateOthers, - // Parse sdp audio state. - SrsRtspSdpStateAudio, - // Parse sdp video state. - SrsRtspSdpStateVideo, -}; - -// 10 Method Definitions, @see rfc2326-1998-rtsp.pdf, page 57 -// The method token indicates the method to be performed on the resource -// identified by the Request-URI. The method is case-sensitive. New -// methods may be defined in the future. Method names may not start with -// a $ character (decimal 24) and must be a token. Methods are -// summarized in Table 2. -// Notes on Table 2: PAUSE is recommended, but not required in that a -// fully functional server can be built that does not support this -// method, for example, for live feeds. If a server does not support a -// particular method, it MUST return "501 Not Implemented" and a client -// SHOULD not try this method again for this server. -enum SrsRtspMethod -{ - SrsRtspMethodDescribe = 0x0001, - SrsRtspMethodAnnounce = 0x0002, - SrsRtspMethodGetParameter = 0x0004, - SrsRtspMethodOptions = 0x0008, - SrsRtspMethodPause = 0x0010, - SrsRtspMethodPlay = 0x0020, - SrsRtspMethodRecord = 0x0040, - SrsRtspMethodRedirect = 0x0080, - SrsRtspMethodSetup = 0x0100, - SrsRtspMethodSetParameter = 0x0200, - SrsRtspMethodTeardown = 0x0400, -}; - -// The state of rtsp token. -enum SrsRtspTokenState -{ - // Parse token failed, default state. - SrsRtspTokenStateError = 100, - // When SP follow the token. - SrsRtspTokenStateNormal = 101, - // When CRLF follow the token. - SrsRtspTokenStateEOF = 102, -}; - -// The rtp packet. -// 5. RTP Data Transfer Protocol, @see rfc3550-2003-rtp.pdf, page 12 -class SrsRtspPacket -{ -public: - // The version (V): 2 bits - // This field identifies the version of RTP. The version defined by this specification is two (2). - // (The value 1 is used by the first draft version of RTP and the value 0 is used by the protocol - // initially implemented in the \vat" audio tool.) - int8_t version; //2bits - // The padding (P): 1 bit - // If the padding bit is set, the packet contains one or more additional padding octets at the - // end which are not part of the payload. The last octet of the padding contains a count of - // how many padding octets should be ignored, including itself. Padding may be needed by - // some encryption algorithms with fixed block sizes or for carrying several RTP packets in a - // lower-layer protocol data unit. - int8_t padding; //1bit - // The extension (X): 1 bit - // If the extension bit is set, the fixed header must be followed by exactly one header extension, - // with a format defined in Section 5.3.1. - int8_t extension; //1bit - // The CSRC count (CC): 4 bits - // The CSRC count contains the number of CSRC identifiers that follow the fixed header. - int8_t csrc_count; //4bits - // The marker (M): 1 bit - // The interpretation of the marker is defined by a profile. It is intended to allow significant - // events such as frame boundaries to be marked in the packet stream. A profile may define - // additional marker bits or specify that there is no marker bit by changing the number of bits - // in the payload type field (see Section 5.3). - int8_t marker; //1bit - // The payload type (PT): 7 bits - // This field identifies the format of the RTP payload and determines its interpretation by the - // application. A profile may specify a default static mapping of payload type codes to payload - // formats. Additional payload type codes may be defined dynamically through non-RTP means - // (see Section 3). A set of default mappings for audio and video is specified in the companion - // RFC 3551 [1]. An RTP source may change the payload type during a session, but this field - // should not be used for multiplexing separate media streams (see Section 5.2). - // A receiver must ignore packets with payload types that it does not understand. - int8_t payload_type; //7bits - // The sequence number: 16 bits - // The sequence number increments by one for each RTP data packet sent, and may be used - // by the receiver to detect packet loss and to restore packet sequence. The initial value of the - // sequence number should be random (unpredictable) to make known-plaintext attacks on - // encryption more dicult, even if the source itself does not encrypt according to the method - // in Section 9.1, because the packets may flow through a translator that does. Techniques for - // choosing unpredictable numbers are discussed in [17]. - uint16_t sequence_number; //16bits - // The timestamp: 32 bits - // The timestamp reflects the sampling instant of the first octet in the RTP data packet. The - // sampling instant must be derived from a clock that increments monotonically and linearly - // in time to allow synchronization and jitter calculations (see Section 6.4.1). The resolution - // of the clock must be sucient for the desired synchronization accuracy and for measuring - // packet arrival jitter (one tick per video frame is typically not sucient). The clock frequency - // is dependent on the format of data carried as payload and is specified statically in the profile - // or payload format specification that defines the format, or may be specified dynamically for - // payload formats defined through non-RTP means. If RTP packets are generated periodically, - // The nominal sampling instant as determined from the sampling clock is to be used, not a - // reading of the system clock. As an example, for fixed-rate audio the timestamp clock would - // likely increment by one for each sampling period. If an audio application reads blocks covering - // 160 sampling periods from the input device, the timestamp would be increased by 160 for - // each such block, regardless of whether the block is transmitted in a packet or dropped as - // silent. - // - // The initial value of the timestamp should be random, as for the sequence number. Several - // consecutive RTP packets will have equal timestamps if they are (logically) generated at once, - // e.g., belong to the same video frame. Consecutive RTP packets may contain timestamps that - // are not monotonic if the data is not transmitted in the order it was sampled, as in the case - // of MPEG interpolated video frames. (The sequence numbers of the packets as transmitted - // will still be monotonic.) - // - // RTP timestamps from different media streams may advance at different rates and usually - // have independent, random offsets. Therefore, although these timestamps are sucient to - // reconstruct the timing of a single stream, directly comparing RTP timestamps from different - // media is not effective for synchronization. Instead, for each medium the RTP timestamp - // is related to the sampling instant by pairing it with a timestamp from a reference clock - // (wallclock) that represents the time when the data corresponding to the RTP timestamp was - // sampled. The reference clock is shared by all media to be synchronized. The timestamp - // pairs are not transmitted in every data packet, but at a lower rate in RTCP SR packets as - // described in Section 6.4. - // - // The sampling instant is chosen as the point of reference for the RTP timestamp because it is - // known to the transmitting endpoint and has a common definition for all media, independent - // of encoding delays or other processing. The purpose is to allow synchronized presentation of - // all media sampled at the same time. - // - // Applications transmitting stored data rather than data sampled in real time typically use a - // virtual presentation timeline derived from wallclock time to determine when the next frame - // or other unit of each medium in the stored data should be presented. In this case, the RTP - // timestamp would reflect the presentation time for each unit. That is, the RTP timestamp for - // each unit would be related to the wallclock time at which the unit becomes current on the - // virtual presentation timeline. Actual presentation occurs some time later as determined by - // The receiver. - // - // An example describing live audio narration of prerecorded video illustrates the significance - // of choosing the sampling instant as the reference point. In this scenario, the video would - // be presented locally for the narrator to view and would be simultaneously transmitted using - // RTP. The sampling instant" of a video frame transmitted in RTP would be established by - // referencing its timestamp to the wallclock time when that video frame was presented to the - // narrator. The sampling instant for the audio RTP packets containing the narrator's speech - // would be established by referencing the same wallclock time when the audio was sampled. - // The audio and video may even be transmitted by different hosts if the reference clocks on - // The two hosts are synchronized by some means such as NTP. A receiver can then synchronize - // presentation of the audio and video packets by relating their RTP timestamps using the - // timestamp pairs in RTCP SR packets. - uint32_t timestamp; //32bits - // The SSRC: 32 bits - // The SSRC field identifies the synchronization source. This identifier should be chosen - // randomly, with the intent that no two synchronization sources within the same RTP session - // will have the same SSRC identifier. An example algorithm for generating a random identifier - // is presented in Appendix A.6. Although the probability of multiple sources choosing the same - // identifier is low, all RTP implementations must be prepared to detect and resolve collisions. - // Section 8 describes the probability of collision along with a mechanism for resolving collisions - // and detecting RTP-level forwarding loops based on the uniqueness of the SSRC identifier. If - // a source changes its source transport address, it must also choose a new SSRC identifier to - // avoid being interpreted as a looped source (see Section 8.2). - uint32_t ssrc; //32bits - - // The payload. - SrsSimpleStream* payload; - // Whether transport in chunked payload. - bool chunked; - // Whether message is completed. - // normal message always completed. - // while chunked completed when the last chunk arriaved. - bool completed; - - // The audio samples, one rtp packets may contains multiple audio samples. - SrsAudioFrame* audio; -public: - SrsRtspPacket(); - virtual ~SrsRtspPacket(); -public: - // copy the header from src. - virtual void copy(SrsRtspPacket* src); - // reap the src to this packet, reap the payload. - virtual void reap(SrsRtspPacket* src); - // decode rtp packet from stream. - virtual srs_error_t decode(SrsBuffer* stream); -private: - virtual srs_error_t decode_97(SrsBuffer* stream); - virtual srs_error_t decode_96(SrsBuffer* stream); -}; - -// The sdp in announce, @see rfc2326-1998-rtsp.pdf, page 159 -// Appendix C: Use of SDP for RTSP Session Descriptions -// The Session Description Protocol (SDP, RFC 2327 [6]) may be used to -// describe streams or presentations in RTSP. -class SrsRtspSdp -{ -private: - SrsRtspSdpState state; -public: - // The version of sdp. - std::string version; - // The owner/creator of sdp. - std::string owner_username; - std::string owner_session_id; - std::string owner_session_version; - std::string owner_network_type; - std::string owner_address_type; - std::string owner_address; - // The session name of sdp. - std::string session_name; - // The connection info of sdp. - std::string connection_network_type; - std::string connection_address_type; - std::string connection_address; - // The tool attribute of sdp. - std::string tool; - // The video attribute of sdp. - std::string video_port; - std::string video_protocol; - std::string video_transport_format; - std::string video_bandwidth_kbps; - std::string video_codec; - std::string video_sample_rate; - std::string video_stream_id; - // The fmtp - std::string video_packetization_mode; - std::string video_sps; // sequence header: sps. - std::string video_pps; // sequence header: pps. - // The audio attribute of sdp. - std::string audio_port; - std::string audio_protocol; - std::string audio_transport_format; - std::string audio_bandwidth_kbps; - std::string audio_codec; - std::string audio_sample_rate; - std::string audio_channel; - std::string audio_stream_id; - // The fmtp - std::string audio_profile_level_id; - std::string audio_mode; - std::string audio_size_length; - std::string audio_index_length; - std::string audio_index_delta_length; - std::string audio_sh; // sequence header. -public: - SrsRtspSdp(); - virtual ~SrsRtspSdp(); -public: - // Parse a line of token for sdp. - virtual srs_error_t parse(std::string token); -private: - // generally, the fmtp is the sequence header for video or audio. - virtual srs_error_t parse_fmtp_attribute(std::string attr); - // generally, the control is the stream info for video or audio. - virtual srs_error_t parse_control_attribute(std::string attr); - // decode the string by base64. - virtual std::string base64_decode(std::string value); -}; - -// The rtsp transport. -// 12.39 Transport, @see rfc2326-1998-rtsp.pdf, page 115 -// This request header indicates which transport protocol is to be used -// and configures its parameters such as destination address, -// compression, multicast time-to-live and destination port for a single -// stream. It sets those values not already determined by a presentation -// description. -class SrsRtspTransport -{ -public: - // The syntax for the transport specifier is - // transport/profile/lower-transport - std::string transport; - std::string profile; - std::string lower_transport; - // unicast | multicast - // mutually exclusive indication of whether unicast or multicast - // delivery will be attempted. Default value is multicast. - // Clients that are capable of handling both unicast and - // multicast transmission MUST indicate such capability by - // including two full transport-specs with separate parameters - // For each. - std::string cast_type; - // The mode parameter indicates the methods to be supported for - // this session. Valid values are PLAY and RECORD. If not - // provided, the default is PLAY. - std::string mode; - // This parameter provides the unicast RTP/RTCP port pair on - // which the client has chosen to receive media data and control - // information. It is specified as a range, e.g., - // client_port=3456-3457. - // where client will use port in: - // [client_port_min, client_port_max) - int client_port_min; - int client_port_max; -public: - SrsRtspTransport(); - virtual ~SrsRtspTransport(); -public: - // Parse a line of token for transport. - virtual srs_error_t parse(std::string attr); -}; - -// The rtsp request message. -// 6 Request, @see rfc2326-1998-rtsp.pdf, page 39 -// A request message from a client to a server or vice versa includes, -// within the first line of that message, the method to be applied to -// The resource, the identifier of the resource, and the protocol -// version in use. -// Request = Request-Line ; Section 6.1 -// // ( general-header ; Section 5 -// | request-header ; Section 6.2 -// | entity-header ) ; Section 8.1 -// CRLF -// [ message-body ] ; Section 4.3 -class SrsRtspRequest -{ -public: - // 6.1 Request Line - // Request-Line = Method SP Request-URI SP RTSP-Version CRLF - std::string method; - std::string uri; - std::string version; - // 12.17 CSeq - // The CSeq field specifies the sequence number for an RTSP requestresponse - // pair. This field MUST be present in all requests and - // responses. For every RTSP request containing the given sequence - // number, there will be a corresponding response having the same - // number. Any retransmitted request must contain the same sequence - // number as the original (i.e. the sequence number is not incremented - // For retransmissions of the same request). - long seq; - // 12.16 Content-Type, @see rfc2326-1998-rtsp.pdf, page 99 - // See [H14.18]. Note that the content types suitable for RTSP are - // likely to be restricted in practice to presentation descriptions and - // parameter-value types. - std::string content_type; - // 12.14 Content-Length, @see rfc2326-1998-rtsp.pdf, page 99 - // This field contains the length of the content of the method (i.e. - // after the double CRLF following the last header). Unlike HTTP, it - // MUST be included in all messages that carry content beyond the header - // portion of the message. If it is missing, a default value of zero is - // assumed. It is interpreted according to [H14.14]. - long content_length; - // The session id. - std::string session; - - // The sdp in announce, NULL for no sdp. - SrsRtspSdp* sdp; - // The transport in setup, NULL for no transport. - SrsRtspTransport* transport; - // For setup message, parse the stream id from uri. - int stream_id; -public: - SrsRtspRequest(); - virtual ~SrsRtspRequest(); -public: - virtual bool is_options(); - virtual bool is_announce(); - virtual bool is_setup(); - virtual bool is_record(); -}; - -// The rtsp response message. -// 7 Response, @see rfc2326-1998-rtsp.pdf, page 43 -// [H6] applies except that HTTP-Version is replaced by RTSP-Version. -// Also, RTSP defines additional status codes and does not define some -// HTTP codes. The valid response codes and the methods they can be used -// with are defined in Table 1. -// After receiving and interpreting a request message, the recipient -// responds with an RTSP response message. -// Response = Status-Line ; Section 7.1 -// // ( general-header ; Section 5 -// | response-header ; Section 7.1.2 -// | entity-header ) ; Section 8.1 -// CRLF -// [ message-body ] ; Section 4.3 -class SrsRtspResponse -{ -public: - // 7.1 Status-Line - // The first line of a Response message is the Status-Line, consisting - // of the protocol version followed by a numeric status code, and the - // textual phrase associated with the status code, with each element - // separated by SP characters. No CR or LF is allowed except in the - // final CRLF sequence. - // Status-Line = RTSP-Version SP Status-Code SP Reason-Phrase CRLF - // @see about the version of rtsp, see SRS_RTSP_VERSION - // @see about the status of rtsp, see SRS_CONSTS_RTSP_OK - int status; - // 12.17 CSeq, @see rfc2326-1998-rtsp.pdf, page 99 - // The CSeq field specifies the sequence number for an RTSP requestresponse - // pair. This field MUST be present in all requests and - // responses. For every RTSP request containing the given sequence - // number, there will be a corresponding response having the same - // number. Any retransmitted request must contain the same sequence - // number as the original (i.e. the sequence number is not incremented - // For retransmissions of the same request). - long seq; - // The session id. - std::string session; -public: - SrsRtspResponse(int cseq); - virtual ~SrsRtspResponse(); -public: - // Encode message to string. - virtual srs_error_t encode(std::stringstream& ss); -protected: - // Sub classes override this to encode the headers. - virtual srs_error_t encode_header(std::stringstream& ss); -}; - -// 10.1 OPTIONS, @see rfc2326-1998-rtsp.pdf, page 59 -// The behavior is equivalent to that described in [H9.2]. An OPTIONS -// request may be issued at any time, e.g., if the client is about to -// try a nonstandard request. It does not influence server state. -class SrsRtspOptionsResponse : public SrsRtspResponse -{ -public: - // Join of SrsRtspMethod - SrsRtspMethod methods; -public: - SrsRtspOptionsResponse(int cseq); - virtual ~SrsRtspOptionsResponse(); -protected: - virtual srs_error_t encode_header(std::stringstream& ss); -}; - -// 10.4 SETUP, @see rfc2326-1998-rtsp.pdf, page 65 -// The SETUP request for a URI specifies the transport mechanism to be -// used for the streamed media. A client can issue a SETUP request for a -// stream that is already playing to change transport parameters, which -// a server MAY allow. If it does not allow this, it MUST respond with -// error "455 Method Not Valid In This State". For the benefit of any -// intervening firewalls, a client must indicate the transport -// parameters even if it has no influence over these parameters, for -// example, where the server advertises a fixed multicast address. -class SrsRtspSetupResponse : public SrsRtspResponse -{ -public: - // The client specified port. - int client_port_min; - int client_port_max; - // The client will use the port in: - // [local_port_min, local_port_max) - int local_port_min; - int local_port_max; - // The session. - std::string session; -public: - SrsRtspSetupResponse(int cseq); - virtual ~SrsRtspSetupResponse(); -protected: - virtual srs_error_t encode_header(std::stringstream& ss); -}; - -// The rtsp protocol stack to parse the rtsp packets. -class SrsRtspStack -{ -private: - // The cached bytes buffer. - SrsSimpleStream* buf; - // The underlayer socket object, send/recv bytes. - ISrsProtocolReadWriter* skt; -public: - SrsRtspStack(ISrsProtocolReadWriter* s); - virtual ~SrsRtspStack(); -public: - // Recv rtsp message from underlayer io. - // @param preq the output rtsp request message, which user must free it. - // @return an int error code. - // ERROR_RTSP_REQUEST_HEADER_EOF indicates request header EOF. - virtual srs_error_t recv_message(SrsRtspRequest** preq); - // Send rtsp message over underlayer io. - // @param res the rtsp response message, which user should never free it. - // @return an int error code. - virtual srs_error_t send_message(SrsRtspResponse* res); -private: - // Recv the rtsp message. - virtual srs_error_t do_recv_message(SrsRtspRequest* req); - // Read a normal token from io, error when token state is not normal. - virtual srs_error_t recv_token_normal(std::string& token); - // Read a normal token from io, error when token state is not eof. - virtual srs_error_t recv_token_eof(std::string& token); - // Read the token util got eof, for example, to read the response status Reason-Phrase - // @param pconsumed, output the token parsed length. NULL to ignore. - virtual srs_error_t recv_token_util_eof(std::string& token, int* pconsumed = NULL); - // Read a token from io, split by SP, endswith CRLF: - // token1 SP token2 SP ... tokenN CRLF - // @param token, output the read token. - // @param state, output the token parse state. - // @param normal_ch, the char to indicates the normal token. - // the SP use to indicates the normal token, @see SRS_RTSP_SP - // the 0x00 use to ignore normal token flag. @see recv_token_util_eof - // @param pconsumed, output the token parsed length. NULL to ignore. - virtual srs_error_t recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch = SRS_RTSP_SP, int* pconsumed = NULL); -}; - -#endif -