diff --git a/trunk/configure b/trunk/configure index d233f66db..5efe7eb59 100755 --- a/trunk/configure +++ b/trunk/configure @@ -254,7 +254,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtc_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") diff --git a/trunk/research/players/srs_rtc_player.html b/trunk/research/players/srs_rtc_player.html new file mode 100644 index 000000000..bbb605ab5 --- /dev/null +++ b/trunk/research/players/srs_rtc_player.html @@ -0,0 +1,90 @@ + + + + + + + + +rtc_media_player:
+ + + + + + + diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 2a7b98bd3..315ec58f7 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3486,7 +3486,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" && n != "max_connections" && n != "daemon" && n != "heartbeat" && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms" - && n != "http_server" && n != "stream_caster" && n != "srt_server" + && n != "http_server" && n != "stream_caster" && n != "rtc" && n != "srt_server" && n != "utc_time" && n != "work_dir" && n != "asprocess" && n != "ff_log_level" && n != "grace_final_wait" && n != "force_grace_quit" && n != "grace_start_wait" @@ -4216,6 +4216,45 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* conf) return ::atoi(conf->arg0().c_str()); } +int SrsConfig::get_rtc_enabled() +{ + SrsConfDirective* conf = root->get("rtc"); + return get_rtc_enabled(conf); +} + +bool SrsConfig::get_rtc_enabled(SrsConfDirective* conf) +{ + static bool DEFAULT = false; + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +int SrsConfig::get_rtc_listen() +{ + static int DEFAULT = 9527; + + SrsConfDirective* conf = root->get("rtc"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("listen"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return ::atoi(conf->arg0().c_str()); +} + SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 6a58f2ef8..1f85550f7 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -490,6 +490,13 @@ public: virtual int get_stream_caster_rtp_port_min(SrsConfDirective* conf); // Get the max udp port for rtp of stream caster rtsp. virtual int get_stream_caster_rtp_port_max(SrsConfDirective* conf); + +// rtc section +public: + virtual int get_rtc_enabled(); + virtual bool get_rtc_enabled(SrsConfDirective* conf); + virtual int get_rtc_listen(); + // vhost specified section public: // Get the vhost directive by vhost name. diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 5355068eb..634ba647c 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -47,6 +47,73 @@ using namespace std; #include #include +string test_sdp = +"v=0\\r\\n" +"o=- 0 0 IN IP4 127.0.0.1\\r\\n" +"s=-\\r\\n" +"t=0 0\\r\\n" +"a=ice-lite\\r\\n" +"a=group:BUNDLE 0 1\\r\\n" +"a=msid-semantic: WMS 6VrfBKXrwK\\r\\n" +"m=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\n" +"c=IN IP4 0.0.0.0\\r\\n" +"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" +"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" +"a=ice-ufrag:xiaozhihongjohn\\r\\n" +"a=ice-pwd:simple_rtmp_server__john\\r\\n" +"a=ice-options:trickle\\r\\n" +"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" +"a=sendrecv\\r\\n" +"a=mid:0\\r\\n" +"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\n" +"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" +"a=rtcp-mux\\r\\n" +"a=rtpmap:111 opus/48000/2\\r\\n" +"a=fmtp:111 minptime=10;useinbandfec=1\\r\\n" +"a=maxptime:60\\r\\n" +"a=ssrc:3233846890 cname:o/i14u9pJrxRKAsu\\r\\n" +"a=ssrc:3233846890 msid:6VrfBKXrwK a0\\r\\n" +"a=ssrc:3233846890 mslabel:6VrfBKXrwK\\r\\n" +"a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" +"m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" +"c=IN IP4 0.0.0.0\\r\\n" +"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" +"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" +"b=as:2000000\\r\\n" +"a=ice-ufrag:xiaozhihongjohn\\r\\n" +"a=ice-pwd:simple_rtmp_server__john\\r\\n" +"a=ice-options:trickle\\r\\n" +"a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\\r\\n" +"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" +"a=extmap:4 urn:3gpp:video-orientation\\r\\n" +"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" +"a=sendrecv\\r\\n" +"a=mid:1\\r\\n" +"a=rtcp-mux\\r\\n" +"a=rtpmap:96 VP8/90000\\r\\n" +"a=rtcp-fb:96 ccm fir\\r\\n" +"a=rtcp-fb:96 nack\\r\\n" +"a=rtcp-fb:96 nack pli\\r\\n" +"a=rtcp-fb:96 goog-remb\\r\\n" +"a=rtcp-fb:96 transport-cc\\r\\n" +"a=rtpmap:98 VP9/90000\\r\\n" +"a=rtcp-fb:98 ccm fir\\r\\n" +"a=rtcp-fb:98 nack\\r\\n" +"a=rtcp-fb:98 nack pli\\r\\n" +"a=rtcp-fb:98 goog-remb\\r\\n" +"a=rtcp-fb:98 transport-cc\\r\\n" +"a=rtpmap:102 H264/90000\\r\\n" +"a=rtcp-fb:102 goog-remb\\r\\n" +"a=rtcp-fb:102 transport-cc\\r\\n" +"a=rtcp-fb:102 ccm fir \\r\\n" +"a=rtcp-fb:102 nack\\r\\n" +"a=rtcp-fb:102 nack pli \\r\\n" +"a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n" +"a=ssrc:3233846889 cname:o/i14u9pJrxRKAsu\\r\\n" +"a=ssrc:3233846889 msid:6VrfBKXrwK v0\\r\\n" +"a=ssrc:3233846889 mslabel:6VrfBKXrwK\\r\\n" +"a=ssrc:3233846889 label:6VrfBKXrwKv0\\r\\n"; + srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) { srs_error_t err = srs_success; @@ -780,6 +847,44 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } +SrsGoApiSdp::SrsGoApiSdp() +{ +} + +SrsGoApiSdp::~SrsGoApiSdp() +{ +} + +srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) +{ + srs_error_t err = srs_success; + + SrsStatistic* stat = SrsStatistic::instance(); + + // path: {pattern}{stream_id} + // e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100 + int sid = r->parse_rest_id(entry->pattern); + + SrsStatisticStream* stream = NULL; + if (sid >= 0 && (stream = stat->find_stream(sid)) == NULL) { + return srs_api_response_code(w, r, ERROR_RTMP_STREAM_NOT_FOUND); + } + + SrsJsonObject* obj = SrsJsonAny::object(); + SrsAutoFree(SrsJsonObject, obj); + + obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); + obj->set("server", SrsJsonAny::integer(stat->server_id())); + + if (r->is_http_post()) { + obj->set("sdp", SrsJsonAny::str(test_sdp.c_str())); + } else { + return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); + } + + return srs_api_response(w, r, obj->dumps()); +} + SrsGoApiClients::SrsGoApiClients() { } diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 5957ff2f3..367edabab 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -164,6 +164,15 @@ public: virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); }; +class SrsGoApiSdp : public ISrsHttpHandler +{ +public: + SrsGoApiSdp(); + virtual ~SrsGoApiSdp(); +public: + virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); +}; + class SrsGoApiClients : public ISrsHttpHandler { public: diff --git a/trunk/src/app/srs_app_rtc_udp.cpp b/trunk/src/app/srs_app_rtc_udp.cpp new file mode 100644 index 000000000..4866c387a --- /dev/null +++ b/trunk/src/app/srs_app_rtc_udp.cpp @@ -0,0 +1,89 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SrsRtcOverUdp::SrsRtcOverUdp() +{ +} + +SrsRtcOverUdp::~SrsRtcOverUdp() +{ +} + +srs_error_t SrsRtcOverUdp::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) +{ + char address_string[64]; + char port_string[16]; + if(getnameinfo(from, fromlen, + (char*)&address_string, sizeof(address_string), + (char*)&port_string, sizeof(port_string), + NI_NUMERICHOST|NI_NUMERICSERV)) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); + } + std::string peer_ip = std::string(address_string); + int peer_port = atoi(port_string); + + srs_error_t err = on_udp_bytes(peer_ip, peer_port, buf, nb_buf); + if (err != srs_success) { + return srs_error_wrap(err, "process udp"); + } + return err; +} + +srs_error_t SrsRtcOverUdp::on_udp_bytes(string host, int port, char* buf, int nb_buf) +{ + srs_error_t err = srs_success; + + srs_trace("recv rtc udp packet from %s:%d, nb_buf=%d", host.c_str(), port, nb_buf); + + return err; +} diff --git a/trunk/src/app/srs_app_rtc_udp.hpp b/trunk/src/app/srs_app_rtc_udp.hpp new file mode 100644 index 000000000..707b6b830 --- /dev/null +++ b/trunk/src/app/srs_app_rtc_udp.hpp @@ -0,0 +1,52 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_RTC_UDP_HPP +#define SRS_APP_RTC_UDP_HPP + +#include + +struct sockaddr; +#include +#include + +#include +#include +#include + +// The rtc over udp stream receiver +class SrsRtcOverUdp : virtual public ISrsUdpHandler +{ +private: +public: + SrsRtcOverUdp(); + virtual ~SrsRtcOverUdp(); +// Interface ISrsUdpHandler +public: + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); +private: + virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf); +}; + +#endif + diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index e95b4734e..85483a5b9 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -44,6 +44,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -108,6 +109,8 @@ std::string srs_listener_type2string(SrsListenerType type) return "RTSP"; case SrsListenerFlv: return "HTTP-FLV"; + case SrsListenerRtcOverUdp: + return "RTC over UDP"; default: return "UNKONWN"; } @@ -335,6 +338,45 @@ SrsUdpCasterListener::~SrsUdpCasterListener() srs_freep(caster); } +SrsRtcListener::SrsRtcListener(SrsServer* svr, SrsListenerType t) : SrsListener(svr, t) +{ + srs_assert(type == SrsListenerRtcOverUdp); + rtc = new SrsRtcOverUdp(); +} + +SrsRtcListener::~SrsRtcListener() +{ +} + +srs_error_t SrsRtcListener::listen(std::string i, int p) +{ + srs_error_t err = srs_success; + + // the caller already ensure the type is ok, + // we just assert here for unknown stream caster. + srs_assert(type == SrsListenerRtcOverUdp); + + ip = i; + port = p; + + srs_freep(listener); + listener = new SrsUdpListener(rtc, ip, port); + + if ((err = listener->listen()) != srs_success) { + return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); + } + + // notify the handler the fd changed. + if ((err = rtc->on_stfd_change(listener->stfd())) != srs_success) { + return srs_error_wrap(err, "notify fd change failed"); + } + + string v = srs_listener_type2string(type); + srs_trace("%s listen at udp://%s:%d, fd=%d", v.c_str(), ip.c_str(), port, listener->fd()); + + return err; +} + SrsSignalManager* SrsSignalManager::instance = NULL; SrsSignalManager::SrsSignalManager(SrsServer* s) @@ -728,6 +770,10 @@ srs_error_t SrsServer::listen() if ((err = listen_stream_caster()) != srs_success) { return srs_error_wrap(err, "stream caster listen"); } + + if ((err = listen_rtc()) != srs_success) { + return srs_error_wrap(err, "rtc listen"); + } if ((err = conn_manager->start()) != srs_success) { return srs_error_wrap(err, "connection manager"); @@ -790,6 +836,9 @@ srs_error_t SrsServer::http_handle() if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) { return srs_error_wrap(err, "handle streams"); } + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp())) != srs_success) { + return srs_error_wrap(err, "handle sdp"); + } if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) { return srs_error_wrap(err, "handle clients"); } @@ -1188,6 +1237,35 @@ srs_error_t SrsServer::listen_stream_caster() return err; } +srs_error_t SrsServer::listen_rtc() +{ + srs_error_t err = srs_success; + + close_listeners(SrsListenerRtcOverUdp); + + if (!_srs_config->get_rtc_enabled()) { + return err; + } + + SrsListener* listener = NULL; + + listener = new SrsRtcListener(this, SrsListenerRtcOverUdp); + srs_assert(listener != NULL); + + listeners.push_back(listener); + + int port = _srs_config->get_rtc_listen(); + if (port <= 0) { + return srs_error_new(ERROR_RTC_PORT, "invalid port=%d", port); + } + + if ((err = listener->listen(srs_any_address_for_listener(), port)) != srs_success) { + return srs_error_wrap(err, "listen at %d", port); + } + + return err; +} + void SrsServer::close_listeners(SrsListenerType type) { std::vector::iterator it; diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 28154600e..77b8964df 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -68,6 +68,8 @@ enum SrsListenerType SrsListenerRtsp = 4, // TCP stream, FLV stream over HTTP. SrsListenerFlv = 5, + // UDP sream, rtp over udp + SrsListenerRtcOverUdp = 6, }; // A common tcp listener, for RTMP/HTTP server. @@ -155,6 +157,19 @@ public: virtual ~SrsUdpCasterListener(); }; +// A UDP listener, for udp stream caster server. +class SrsRtcListener : public SrsListener +{ +protected: + SrsUdpListener* listener; + ISrsUdpHandler* rtc; +public: + SrsRtcListener(SrsServer* svr, SrsListenerType t); + virtual ~SrsRtcListener(); +public: + virtual srs_error_t listen(std::string i, int p); +}; + // Convert signal to io, // @see: st-1.9/docs/notes.html class SrsSignalManager : public ISrsCoroutineHandler @@ -284,6 +299,7 @@ private: virtual srs_error_t listen_http_api(); virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_stream_caster(); + virtual srs_error_t listen_rtc(); // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index f7375780a..372a0196a 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -321,6 +321,7 @@ #define ERROR_HTTP_302_INVALID 4038 #define ERROR_BASE64_DECODE 4039 #define ERROR_HTTP_STREAM_EOF 4040 +#define ERROR_RTC_PORT 4041 /////////////////////////////////////////////////////// // HTTP API error.