diff --git a/configure.ac b/configure.ac index 0820bd4adc..31dfec69dc 100644 --- a/configure.ac +++ b/configure.ac @@ -1392,8 +1392,7 @@ livemedia=no livemedia_prefix=/usr AC_ARG_ENABLE(rtsp_server, -[ --enable-rtsp-server enables RTSP server support (default is auto)] -[ Requires: live555 (<= 2015)], +[ --enable-rtsp-server enables RTSP server support (default is auto)], [rtsp_server_req=$enableval], [rtsp_server_req=$build_default] ) @@ -1411,13 +1410,8 @@ if test $rtsp_server_req != no; then CPPFLAGS="$CPPFLAGS $RTSP_SERVER_FLAGS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include - #include - ]], [[ - #if LIVEMEDIA_LIBRARY_VERSION_INT > 1438905600 - #error "Unsuppored live555 version (too new)" - #endif - ]] - )], FOUND_LIVE_H=yes, [echo "liveMedia (live555 library) headers not found or wrong version (< 2015 needed)"; FOUND_LIVE_H=no]) + ]] + )], FOUND_LIVE_H=yes, [echo "liveMedia (live555 library) headers not found"; FOUND_LIVE_H=no]) CPPFLAGS=$SAVED_CPPFLAGS AC_LANG_POP(C++) if test $FOUND_LIVE_H = yes @@ -1426,7 +1420,7 @@ if test $rtsp_server_req != no; then CFLAGS="$CFLAGS $RTSP_SERVER_FLAGS" CXXFLAGS="$CXXFLAGS $RTSP_SERVER_FLAGS" RTSP_SERVER_LIBS="-lliveMedia -lBasicUsageEnvironment -lUsageEnvironment -lgroupsock" - RTSP_SERVER_OBJ="src/rtsp/c_basicRTSPOnlyServer.o src/rtsp/BasicRTSPOnlyServer.o src/rtsp/BasicRTSPOnlySubsession.o src/video_rxtx/h264_rtp.o" + RTSP_SERVER_OBJ="src/rtsp/ultragrid_rtsp.o src/rtsp/UltragridRTSPServer.o src/rtsp/UltragridRTSPSubsession.o src/video_rxtx/h264_rtp.o" add_module video_rxtx_h264 "$RTSP_SERVER_OBJ" "$RTSP_SERVER_LIBS" rtsp_server=yes livemedia=yes diff --git a/src/main.cpp b/src/main.cpp index aee9c0ba91..e091889b47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1474,22 +1474,28 @@ int main(int argc, char *argv[]) params["audio_codec"].l = ac_params.codec; params["audio_sample_rate"].i = IF_NOT_NULL_ELSE(ac_params.sample_rate, kHz48); - params["audio_channels"].i = audio_capture_channels; params["audio_bps"].i = 2; params["a_rx_port"].i = opt.audio.recv_port; params["a_tx_port"].i = opt.audio.send_port; + // override number of channels for OPUS as OPUS does not support mono + if (ac_params.codec == AC_OPUS) { + params["audio_channels"].i = 2; + } else { + params["audio_channels"].i = audio_capture_channels; + } + if (strcmp(opt.video_protocol, "rtsp") == 0) { - rtps_types_t avType; - if(strcmp("none", vidcap_params_get_driver(opt.vidcap_params_head)) != 0 && (strcmp("none",opt.audio.send_cfg) != 0)) avType = av; //AVStream - else if((strcmp("none",opt.audio.send_cfg) != 0)) avType = audio; //AStream - else if(strcmp("none", vidcap_params_get_driver(opt.vidcap_params_head))) avType = video; //VStream + rtsp_media_type_t media_type; + if(strcmp("none", vidcap_params_get_driver(opt.vidcap_params_head)) != 0 && (strcmp("none",opt.audio.send_cfg) != 0)) media_type = av; //AVStream + else if((strcmp("none",opt.audio.send_cfg) != 0)) media_type = audio; //AStream + else if(strcmp("none", vidcap_params_get_driver(opt.vidcap_params_head))) media_type = video; //VStream else { printf("[RTSP SERVER CHECK] no stream type... check capture devices input...\n"); - avType = none; + media_type = none; } - params["avType"].l = (long) avType; + params["media_type"].l = (long) media_type; } sdp_set_properties(opt.requested_receiver, opt.video_rxtx_mode & MODE_SENDER && strcasecmp(opt.video_protocol, "sdp") == 0, opt.audio.send_port != 0 && strcasecmp(opt.audio.proto, "sdp") == 0); diff --git a/src/rtsp/BasicRTSPOnlyServer.cpp b/src/rtsp/BasicRTSPOnlyServer.cpp deleted file mode 100644 index 1e2134ce9b..0000000000 --- a/src/rtsp/BasicRTSPOnlyServer.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * FILE: rtsp/BasicRTSPOnlyServer.cpp - * AUTHORS: David Cassany - * Gerard Castillo - * - * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya - * - * Redistribution and use in source and binary forms, with or without - * modification, is permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by the Fundació i2CAT, - * Internet I Innovació Digital a Catalunya. This product also includes - * software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the University nor of the Institute may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "rtsp/BasicRTSPOnlyServer.hh" -#include "rtsp/BasicRTSPOnlySubsession.hh" - -BasicRTSPOnlyServer *BasicRTSPOnlyServer::srvInstance = NULL; - -BasicRTSPOnlyServer::BasicRTSPOnlyServer(int port, struct module *mod, rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio){ - if(mod == NULL){ - exit(1); - } - this->fPort = port; - this->mod = mod; - this->avType = avType; - this->audio_codec = audio_codec; - this->audio_sample_rate = audio_sample_rate; - this->audio_channels = audio_channels; - this->audio_bps = audio_bps; - this->rtp_port = rtp_port; - this->rtp_port_audio = rtp_port_audio; - this->rtspServer = NULL; - this->env = NULL; - this->srvInstance = this; -} - -BasicRTSPOnlyServer* -BasicRTSPOnlyServer::initInstance(int port, struct module *mod, rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio){ - if (srvInstance != NULL){ - return srvInstance; - } - return new BasicRTSPOnlyServer(port, mod, avType, audio_codec, audio_sample_rate, audio_channels, audio_bps, rtp_port, rtp_port_audio); -} - -BasicRTSPOnlyServer* -BasicRTSPOnlyServer::getInstance(){ - if (srvInstance != NULL){ - return srvInstance; - } - return NULL; -} - -int BasicRTSPOnlyServer::init_server() { - - if (env != NULL || rtspServer != NULL || mod == NULL || (avType >= NUM_RTSP_FORMATS && avType < 0)){ - exit(1); - } - - //setting livenessTimeoutTask - unsigned reclamationTestSeconds = 60; - - TaskScheduler* scheduler = BasicTaskScheduler::createNew(); - env = BasicUsageEnvironment::createNew(*scheduler); - - UserAuthenticationDatabase* authDB = NULL; - #ifdef ACCESS_CONTROL - // To implement client access control to the RTSP server, do the following: - authDB = new UserAuthenticationDatabase; - authDB->addUserRecord("i2cat", "ultragrid"); // replace these with real strings - // Repeat the above with each , that you wish to allow - // access to the server. - #endif - - if (fPort == 0){ - fPort = 8554; - } - - rtspServer = RTSPServer::createNew(*env, fPort, authDB, reclamationTestSeconds); - if (rtspServer == NULL) { - *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; - exit(1); - } - rtspServer->disableStreamingRTPOverTCP(); - ServerMediaSession* sms; - sms = ServerMediaSession::createNew(*env, "ultragrid", - "UltraGrid RTSP server enabling standard transport", - "UltraGrid RTSP server"); - - if(avType == av){ - sms->addSubsession(BasicRTSPOnlySubsession - ::createNew(*env, True, mod, audio, audio_codec, audio_sample_rate, audio_channels, audio_bps, rtp_port, rtp_port_audio)); - sms->addSubsession(BasicRTSPOnlySubsession - ::createNew(*env, True, mod, video, audio_codec, audio_sample_rate, audio_channels, audio_bps, rtp_port, rtp_port_audio)); - }else if(avType == audio){ - sms->addSubsession(BasicRTSPOnlySubsession - ::createNew(*env, True, mod, audio, audio_codec, audio_sample_rate, audio_channels, audio_bps, rtp_port, rtp_port_audio)); - - }else if(avType == video){ - sms->addSubsession(BasicRTSPOnlySubsession - ::createNew(*env, True, mod, video, audio_codec, audio_sample_rate, audio_channels, audio_bps, rtp_port, rtp_port_audio)); - }else{ - *env << "\n[RTSP Server] Error when trying to play stream type: \"" << avType << "\"\n"; - exit(1); - } - - rtspServer->addServerMediaSession(sms); - - char* url = rtspServer->rtspURL(sms); - *env << "\n[RTSP Server] Play this stream using the URL \"" << url << "\"\n"; - delete[] url; - - return 0; -} - -void *BasicRTSPOnlyServer::start_server(void *args){ - char* watch = (char*) args; - BasicRTSPOnlyServer* instance = getInstance(); - - if (instance == NULL || instance->env == NULL || instance->rtspServer == NULL){ - return NULL; - } - - instance->env->taskScheduler().doEventLoop(watch); - - Medium::close(instance->rtspServer); - delete &instance->env->taskScheduler(); - instance->env->reclaim(); - - return NULL; -} diff --git a/src/rtsp/BasicRTSPOnlySubsession.cpp b/src/rtsp/BasicRTSPOnlySubsession.cpp deleted file mode 100644 index 80789e7b62..0000000000 --- a/src/rtsp/BasicRTSPOnlySubsession.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - * FILE: rtsp/BasicRTSPOnlySubsession.cpp - * AUTHORS: David Cassany - * Gerard Castillo - * - * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya - * Copyright (c) 2014-2023 CESNET, z. s. p. o. - * - * Redistribution and use in source and binary forms, with or without - * modification, is permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by the Fundació i2CAT, - * Internet I Innovació Digital a Catalunya. This product also includes - * software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the University nor of the Institute may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "rtsp/BasicRTSPOnlySubsession.hh" -#include -#include -#include - -#include "messaging.h" -#include "utils/macros.h" -#include "utils/sdp.h" - -BasicRTSPOnlySubsession* -BasicRTSPOnlySubsession::createNew(UsageEnvironment& env, - Boolean reuseFirstSource, struct module *mod, rtps_types_t avType, - audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, - int audio_bps, int rtp_port, int rtp_port_audio) { - return new BasicRTSPOnlySubsession(env, reuseFirstSource, mod, avType, - audio_codec, audio_sample_rate, audio_channels, audio_bps, rtp_port, rtp_port_audio); -} - -BasicRTSPOnlySubsession::BasicRTSPOnlySubsession(UsageEnvironment& env, - Boolean reuseFirstSource, struct module *mod, rtps_types_t avType, - audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, - int audio_bps, int rtp_port, int rtp_port_audio) : - ServerMediaSubsession(env), fSDPLines(NULL), fReuseFirstSource( - reuseFirstSource), fLastStreamToken(NULL) { - Vdestination = NULL; - Adestination = NULL; - gethostname(fCNAME, sizeof fCNAME); - this->fmod = mod; - this->avType = avType; - this->audio_codec = audio_codec; - this->audio_sample_rate = audio_sample_rate; - this->audio_channels = audio_channels; - this->audio_bps = audio_bps; - this->rtp_port = rtp_port; - this->rtp_port_audio = rtp_port_audio; - fCNAME[sizeof fCNAME - 1] = '\0'; -} - -BasicRTSPOnlySubsession::~BasicRTSPOnlySubsession() { - delete[] fSDPLines; - delete Adestination; - delete Vdestination; -} - -char const* BasicRTSPOnlySubsession::sdpLines() { - if (fSDPLines == NULL) { - setSDPLines(); - } - return fSDPLines; -} - -void BasicRTSPOnlySubsession::setSDPLines() { - //TODO: should be more dynamic - //VStream - if (avType == video || avType == av) { - unsigned estBitrate = 5000; - char const* mediaType = "video"; - uint8_t rtpPayloadType = 96; - AddressString ipAddressStr(fServerAddressForSDP); - char* rtpmapLine = strdup("a=rtpmap:96 H264/90000\n"); - //char const* auxSDPLine = ""; - - char const* const sdpFmt = "m=%s %u RTP/AVP %u\r\n" - "c=IN IP4 %s\r\n" - "b=AS:%u\r\n" - "a=rtcp:%d\r\n" - "%s" - "a=control:%s\r\n"; - unsigned sdpFmtSize = strlen(sdpFmt) + strlen(mediaType) + 5 /* max short len */ - + 3 /* max char len */ - + strlen(ipAddressStr.val()) + 20 /* max int len */ - + strlen(rtpmapLine) + strlen(trackId()); - char* sdpLines = new char[sdpFmtSize]; - - snprintf(sdpLines, sdpFmtSize, sdpFmt, mediaType, // m= - rtp_port,//fPortNumForSDP, // m= - rtpPayloadType, // m= - ipAddressStr.val(), // c= address - estBitrate, // b=AS: - rtp_port + 1, - rtpmapLine, // a=rtpmap:... (if present) - trackId()); // a=control: - - fSDPLines = sdpLines; - free(rtpmapLine); - } - //AStream - if (avType == audio || avType == av) { - unsigned estBitrate = 384; - char const* mediaType = "audio"; - AddressString ipAddressStr(fServerAddressForSDP); - - char rtpmapLine[STR_LEN]; - //char const* auxSDPLine = ""; - const uint8_t rtpPayloadType = get_audio_rtp_pt_rtpmap( - audio_codec, audio_sample_rate, audio_channels, rtpmapLine); - - char const* const sdpFmt = "m=%s %u RTP/AVP %u\r\n" - "c=IN IP4 %s\r\n" - "b=AS:%u\r\n" - "a=rtcp:%d\r\n" - "%s" - "a=control:%s\r\n"; - unsigned sdpFmtSize = strlen(sdpFmt) + strlen(mediaType) + 5 /* max short len */ - + 3 /* max char len */ - + strlen(ipAddressStr.val()) + 20 /* max int len */ - + strlen(rtpmapLine) + strlen(trackId()); - char* sdpLines = new char[sdpFmtSize]; - - snprintf(sdpLines, sdpFmtSize, sdpFmt, - mediaType, // m= - rtp_port_audio,//fPortNumForSDP, // m= - rtpPayloadType, // m= - ipAddressStr.val(), // c= address - estBitrate, // b=AS: - rtp_port_audio + 1, - rtpmapLine, // a=rtpmap:... (if present) - trackId()); // a=control: - - fSDPLines = sdpLines; - } -} - -void BasicRTSPOnlySubsession::getStreamParameters(unsigned /* clientSessionId */, - netAddressBits clientAddress, Port const& clientRTPPort, - Port const& clientRTCPPort, int /* tcpSocketNum */, - unsigned char /* rtpChannelId */, unsigned char /* rtcpChannelId */, - netAddressBits& destinationAddress, uint8_t& /*destinationTTL*/, - Boolean& /* isMulticast */, Port& serverRTPPort, Port& serverRTCPPort, - void*& /* streamToken */) { - if (avType == video || avType == av) { - Port rtp(rtp_port); - serverRTPPort = rtp; - Port rtcp(rtp_port + 1); - serverRTCPPort = rtcp; - - if (fSDPLines == NULL) { - setSDPLines(); - } - if (destinationAddress == 0) { - destinationAddress = clientAddress; - } - struct in_addr destinationAddr; - destinationAddr.s_addr = destinationAddress; - delete Vdestination; - Vdestination = new Destinations(destinationAddr, clientRTPPort, - clientRTCPPort); - } - if (avType == audio || avType == av) { - Port rtp(rtp_port_audio); - serverRTPPort = rtp; - Port rtcp(rtp_port_audio + 1); - serverRTCPPort = rtcp; - - if (fSDPLines == NULL) { - setSDPLines(); - } - if (destinationAddress == 0) { - destinationAddress = clientAddress; - } - struct in_addr destinationAddr; - destinationAddr.s_addr = destinationAddress; - delete Adestination; - Adestination = new Destinations(destinationAddr, clientRTPPort, - clientRTCPPort); - } -} - -void BasicRTSPOnlySubsession::startStream(unsigned /* clientSessionId */, - void* /* streamToken */, TaskFunc* /* rtcpRRHandler */, - void* /* rtcpRRHandlerClientData */, unsigned short& /* rtpSeqNum */, - unsigned& /* rtpTimestamp */, - ServerRequestAlternativeByteHandler* /* serverRequestAlternativeByteHandler */, - void* /* serverRequestAlternativeByteHandlerClientData */) { - struct response *resp = NULL; - - if (Vdestination != NULL) { - if (avType == video || avType == av) { - char pathV[1024]; - - memset(pathV, 0, sizeof(pathV)); - enum module_class path_sender[] = { MODULE_CLASS_SENDER, - MODULE_CLASS_NONE }; - append_message_path(pathV, sizeof(pathV), path_sender); - - //CHANGE DST PORT - struct msg_sender *msgV1 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - msgV1->tx_port = ntohs(Vdestination->rtpPort.num()); - msgV1->type = SENDER_MSG_CHANGE_PORT; - resp = send_message(fmod, pathV, (struct message *) msgV1); - free_response(resp); - - //CHANGE DST ADDRESS - struct msg_sender *msgV2 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - strncpy(msgV2->receiver, inet_ntoa(Vdestination->addr), - sizeof(msgV2->receiver) - 1); - msgV2->type = SENDER_MSG_CHANGE_RECEIVER; - - resp = send_message(fmod, pathV, (struct message *) msgV2); - free_response(resp); - } - } - - if (Adestination != NULL) { - if (avType == audio || avType == av) { - char pathA[1024]; - - memset(pathA, 0, sizeof(pathA)); - enum module_class path_sender[] = { MODULE_CLASS_AUDIO, - MODULE_CLASS_SENDER, MODULE_CLASS_NONE }; - append_message_path(pathA, sizeof(pathA), path_sender); - - //CHANGE DST PORT - struct msg_sender *msgA1 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - msgA1->tx_port = ntohs(Adestination->rtpPort.num()); - msgA1->type = SENDER_MSG_CHANGE_PORT; - resp = send_message(fmod, pathA, (struct message *) msgA1); - free_response(resp); - resp = NULL; - - //CHANGE DST ADDRESS - struct msg_sender *msgA2 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - strncpy(msgA2->receiver, inet_ntoa(Adestination->addr), - sizeof(msgA2->receiver) - 1); - msgA2->type = SENDER_MSG_CHANGE_RECEIVER; - - resp = send_message(fmod, pathA, (struct message *) msgA2); - free_response(resp); - resp = NULL; - } - } -} - -void BasicRTSPOnlySubsession::deleteStream(unsigned /* clientSessionId */, - void*& /* streamToken */) { - if (Vdestination != NULL) { - if (avType == video || avType == av) { - char pathV[1024]; - delete Vdestination; - Vdestination = NULL; - memset(pathV, 0, sizeof(pathV)); - enum module_class path_sender[] = { MODULE_CLASS_SENDER, - MODULE_CLASS_NONE }; - append_message_path(pathV, sizeof(pathV), path_sender); - - //CHANGE DST PORT - struct msg_sender *msgV1 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - msgV1->tx_port = rtp_port; - msgV1->type = SENDER_MSG_CHANGE_PORT; - struct response *resp; - resp = send_message(fmod, pathV, (struct message *) msgV1); - free_response(resp); - - //CHANGE DST ADDRESS - struct msg_sender *msgV2 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - strncpy(msgV2->receiver, "127.0.0.1", sizeof(msgV2->receiver) - 1); - msgV2->type = SENDER_MSG_CHANGE_RECEIVER; - resp = send_message(fmod, pathV, (struct message *) msgV2); - free_response(resp); - } - } - - if (Adestination != NULL) { - if (avType == audio || avType == av) { - char pathA[1024]; - delete Vdestination; - Adestination = NULL; - memset(pathA, 0, sizeof(pathA)); - enum module_class path_sender[] = { MODULE_CLASS_AUDIO, - MODULE_CLASS_SENDER, MODULE_CLASS_NONE }; - append_message_path(pathA, sizeof(pathA), path_sender); - - //CHANGE DST PORT - struct msg_sender *msgA1 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - - //TODO: GET AUDIO PORT SET (NOT A COMMON CASE WHEN RTSP IS ENABLED: DEFAULT -> vport + 2) - msgA1->tx_port = rtp_port_audio; - msgA1->type = SENDER_MSG_CHANGE_PORT; - struct response *resp; - resp = send_message(fmod, pathA, (struct message *) msgA1); - free_response(resp); - - //CHANGE DST ADDRESS - struct msg_sender *msgA2 = (struct msg_sender *) new_message( - sizeof(struct msg_sender)); - strncpy(msgA2->receiver, "127.0.0.1", sizeof(msgA2->receiver) - 1); - msgA2->type = SENDER_MSG_CHANGE_RECEIVER; - resp = send_message(fmod, pathA, (struct message *) msgA2); - free_response(resp); - } - } -} -/* vi: set noexpandtab: */ diff --git a/src/rtsp/BasicRTSPOnlySubsession.hh b/src/rtsp/BasicRTSPOnlySubsession.hh deleted file mode 100644 index f68484013b..0000000000 --- a/src/rtsp/BasicRTSPOnlySubsession.hh +++ /dev/null @@ -1,154 +0,0 @@ -/* - * FILE: rtsp/BasicRTSPOnlySubsession.hh - * AUTHORS: David Cassany - * Gerard Castillo - * - * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya - * - * Redistribution and use in source and binary forms, with or without - * modification, is permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by the Fundació i2CAT, - * Internet I Innovació Digital a Catalunya. This product also includes - * software developed by CESNET z.s.p.o. - * - * 4. Neither the name of the University nor of the Institute may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#ifndef _BASIC_RTSP_ONLY_SUBSESSION_HH -#define _BASIC_RTSP_ONLY_SUBSESSION_HH - -#ifndef _SERVER_MEDIA_SESSION_HH -#include -#endif - -#include "rtsp/rtsp_utils.h" -#include "audio/types.h" -#include "module.h" -#include "control_socket.h" - -// #ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH -// #include -// #endif - -class Destinations { -public: - Destinations(struct in_addr const& destAddr, - Port const& rtpDestPort, - Port const& rtcpDestPort) -: isTCP(False), addr(destAddr), rtpPort(rtpDestPort), rtcpPort(rtcpDestPort), - tcpSocketNum(0), rtpChannelId(0), rtcpChannelId(0) - { - } - Destinations(int tcpSockNum, unsigned char rtpChanId, unsigned char rtcpChanId) - : isTCP(True), rtpPort(0) /*dummy*/, rtcpPort(0) /*dummy*/, - tcpSocketNum(tcpSockNum), rtpChannelId(rtpChanId), rtcpChannelId(rtcpChanId) { - } - -public: - Boolean isTCP; - struct in_addr addr; - Port rtpPort; - Port rtcpPort; - int tcpSocketNum; - unsigned char rtpChannelId, rtcpChannelId; -}; - -#ifdef __clang__ -#define MAYBE_UNUSED_ATTRIBUTE [[maybe_unused]] -#else -#define MAYBE_UNUSED_ATTRIBUTE // GCC complains if [[maybe_used]] is used there -#endif - -class BasicRTSPOnlySubsession: public ServerMediaSubsession { - -public: - static BasicRTSPOnlySubsession* - createNew(UsageEnvironment& env, - Boolean reuseFirstSource, - struct module *mod, - rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio); - -protected: - - BasicRTSPOnlySubsession(UsageEnvironment& env, Boolean reuseFirstSource, - struct module *mod, rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio); - - virtual ~BasicRTSPOnlySubsession(); - - virtual char const* sdpLines(); - - virtual void getStreamParameters(unsigned clientSessionId, - netAddressBits clientAddress, - Port const& clientRTPPort, - Port const& clientRTCPPort, - int tcpSocketNum, - unsigned char rtpChannelId, - unsigned char rtcpChannelId, - netAddressBits& destinationAddress, - uint8_t& destinationTTL, - Boolean& isMulticast, - Port& serverRTPPort, - Port& serverRTCPPort, - void*& streamToken); - - virtual void startStream(unsigned clientSessionId, void* streamToken, - TaskFunc* rtcpRRHandler, void* rtcpRRHandlerClientData, - unsigned short& rtpSeqNum, - unsigned& rtpTimestamp, - ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, - void* serverRequestAlternativeByteHandlerClientData); - - virtual void deleteStream(unsigned clientSessionId, void*& streamToken); - -protected: - - char* fSDPLines; - Destinations* Vdestination; - Destinations* Adestination; - -private: - - void setSDPLines(); - - MAYBE_UNUSED_ATTRIBUTE Boolean fReuseFirstSource; - MAYBE_UNUSED_ATTRIBUTE void* fLastStreamToken; - char fCNAME[100]; - struct module *fmod; - rtps_types_t avType; - audio_codec_t audio_codec; - int audio_sample_rate; - int audio_channels; - int audio_bps; - int rtp_port; //server rtp port - int rtp_port_audio; //server rtp port -}; - - -#endif diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp new file mode 100644 index 0000000000..c86dcc37be --- /dev/null +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -0,0 +1,155 @@ +/* + * FILE: rtsp/UltragridRTSPServer.cpp + * AUTHORS: David Cassany + * Gerard Castillo + * Martin Pulec + * Jakub Kováč + * + * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya + * Copyright (c) 2010-2023 CESNET, z. s. p. o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the Fundació i2CAT, + * Internet I Innovació Digital a Catalunya. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University nor of the Institute may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * @note This code was created as a set of steps on file from Live555 library testProgs/testOnDemandRTSPServer.cpp + * Original file licenece is posted below + * @note This file also contains function announceURL what was copied from Live555 library testProgs/announceURL.cpp + * announceURL.cpp licence is the same as in testOnDemandRTSPServer.cpp +*/ +/********** +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. (See .) + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for +more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +**********/ +// Copyright (c) 1996-2023, Live Networks, Inc. All rights reserved + +#include "rtsp/UltragridRTSPServer.hh" +#include "rtsp/UltragridRTSPSubsession.hh" +#include // for "weHaveAnIPv*Address()" + +UltragridRTSPServer::UltragridRTSPServer(unsigned int rtsp_port, struct module* mod, rtsp_media_type_t media_type, audio_codec_t audio_codec, + int audio_sample_rate, int audio_channels, int rtp_video_port, int rtp_audio_port) { + if(mod == NULL) + throw std::system_error(); + + // Begin by setting up our usage environment: + TaskScheduler* scheduler = BasicTaskScheduler::createNew(); + env = BasicUsageEnvironment::createNew(*scheduler); + + UserAuthenticationDatabase* authDB = NULL; + #ifdef ACCESS_CONTROL + // To implement client access control to the RTSP server, do the following: + authDB = new UserAuthenticationDatabase; + authDB->addUserRecord("username1", "password1"); // replace these with real strings + // Repeat the above with each , that you wish to allow + // access to the server. + #endif + + if (rtsp_port == 0) + rtsp_port = 8554; // default port number + + // only trying specified port because using different port than expected could lead to issues + rtspServer = RTSPServer::createNew(*env, rtsp_port, authDB); + if (rtspServer == NULL) { + *env << "[RTSP Server] Error: Failed to create RTSP server: " << env->getResultMsg() << "\n"; + throw std::system_error(); + } + + ServerMediaSession* sms = ServerMediaSession::createNew(*env, "ultragrid", "UltraGrid RTSP server enabling standard transport", "UltraGrid RTSP server"); + + if (media_type == video || media_type == av) + sms->addSubsession(UltragridRTSPVideoSubsession::createNew(*env, mod, rtp_video_port)); + if (media_type == audio || media_type == av) + sms->addSubsession(UltragridRTSPAudioSubsession::createNew(*env, mod, rtp_audio_port, audio_sample_rate, audio_channels, audio_codec)); + + if (media_type == none) { + *env << "\n[RTSP Server] Error: No media type selected: \"none\"\n"; + throw std::system_error(); + } + if (media_type < 0 || media_type >= NUM_RTSP_MEDIA_TYPES) { + *env << "\n[RTSP Server] Error: Incompatible media type for subsession: \"" << media_type << "\"\n"; + throw std::system_error(); + } + + rtspServer->addServerMediaSession(sms); + announceURL(rtspServer, sms); +} + +UltragridRTSPServer::~UltragridRTSPServer() { + if (rtspServer != NULL) { + Medium::close(rtspServer); + } + if (env != NULL) { + delete &env->taskScheduler(); + env->reclaim(); + } +} + +void UltragridRTSPServer::serverRunner(char* serverStopFlag) { + env->taskScheduler().doEventLoop(serverStopFlag); +} + +// copied from Live555 library live555/testProgs/announceURL.cpp, published under LGPL3 licence +void UltragridRTSPServer::announceURL(RTSPServer* rtspServer, ServerMediaSession* sms) { + if (rtspServer == NULL || sms == NULL) return; // sanity check + + UsageEnvironment& env = rtspServer->envir(); + + env << "Play this stream using the URL "; + if (weHaveAnIPv4Address(env)) { + char* url = rtspServer->ipv4rtspURL(sms); + env << "\"" << url << "\""; + delete[] url; + if (weHaveAnIPv6Address(env)) env << " or "; + } + if (weHaveAnIPv6Address(env)) { + char* url = rtspServer->ipv6rtspURL(sms); + env << "\"" << url << "\""; + delete[] url; + } + env << "\n"; +} diff --git a/src/rtsp/BasicRTSPOnlyServer.hh b/src/rtsp/UltragridRTSPServer.hh similarity index 58% rename from src/rtsp/BasicRTSPOnlyServer.hh rename to src/rtsp/UltragridRTSPServer.hh index a437eaacc6..8b26872cbb 100644 --- a/src/rtsp/BasicRTSPOnlyServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -1,9 +1,12 @@ /* - * FILE: rtsp/BasicRTSPOnlyServer.hh + * FILE: rtsp/UltragridRTSPServer.hh * AUTHORS: David Cassany * Gerard Castillo + * Martin Pulec + * Jakub Kováč * * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya + * Copyright (c) 2010-2023 CESNET, z. s. p. o. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions @@ -42,8 +45,8 @@ * */ -#ifndef _BASIC_RTSP_ONLY_SERVER_HH -#define _BASIC_RTSP_ONLY_SERVER_HH +#ifndef ULTRAGRID_RTSP_SERVER_HH +#define ULTRAGRID_RTSP_SERVER_HH #include #include @@ -51,36 +54,43 @@ #include "audio/types.h" #include "module.h" - - -class BasicRTSPOnlyServer { -private: - BasicRTSPOnlyServer(int port, struct module *mod, rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio); - +/** + * Implements these RTSP methods: + * DESCRIBE - creates media description in SDP protocol format + * PLAY - begins stream by changing IP address and port to reciever, simmilar to control port + * TEARDOWN - end stream by changing IP address and port to localhost +*/ +class UltragridRTSPServer { public: - static BasicRTSPOnlyServer* initInstance(int port, struct module *mod, rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio); - static BasicRTSPOnlyServer* getInstance(); + UsageEnvironment* env; - int init_server(); + UltragridRTSPServer(unsigned int rtsp_port, struct module* mod, rtsp_media_type_t media_type, audio_codec_t audio_codec, + int audio_sample_rate, int audio_channels, int rtp_video_port, int rtp_audio_port); + ~UltragridRTSPServer(); - static void *start_server(void *args); + /** + * starts and then runs the server + * returns control after serverStopFlag has been set to 1 + * + * @param serverStopFlag if set to 0 server is running, when changed to 1 server stops + */ + void serverRunner(char* serverStopFlag); - int update_server(); + /** + * Copy constructor and copy assignment operator do not make sense in this context + */ + UltragridRTSPServer(const UltragridRTSPServer&) = delete; + UltragridRTSPServer& operator=(const UltragridRTSPServer&) = delete; private: + /** + * @note Copied as is from live555/testProgs/announceURL.hh. + */ + static void announceURL(RTSPServer* rtspServer, ServerMediaSession* sms); - static BasicRTSPOnlyServer* srvInstance; - int fPort; - struct module *mod; - rtps_types_t avType; - audio_codec_t audio_codec; - int audio_sample_rate; - int audio_channels; - int audio_bps; - int rtp_port; //server rtp port - int rtp_port_audio; //server rtp port RTSPServer* rtspServer; - UsageEnvironment* env; }; -#endif +typedef UltragridRTSPServer BasicRTSPOnlyServer; // kept for legacy maintanance + +#endif // ULTRAGRID_RTSP_SERVER_HH diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp new file mode 100644 index 0000000000..6536ccd8c2 --- /dev/null +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -0,0 +1,201 @@ +/* + * FILE: rtsp/UltragridRTSPSubsession.cpp + * AUTHORS: David Cassany + * Gerard Castillo + * Martin Pulec + * Jakub Kováč + * + * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya + * Copyright (c) 2010-2023 CESNET, z. s. p. o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the Fundació i2CAT, + * Internet I Innovació Digital a Catalunya. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University nor of the Institute may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "rtsp/UltragridRTSPSubsession.hh" +#include "messaging.h" +#include "host.h" + +#ifdef __clang__ +#define MAYBE_UNUSED_ATTRIBUTE [[maybe_unused]] +#else +#define MAYBE_UNUSED_ATTRIBUTE // GCC complains if [[maybe_used]] is used there +#endif + +UltragridRTSPSubsessionCommon::UltragridRTSPSubsessionCommon(UsageEnvironment& env, struct module *mod, int RTPPort, enum module_class *path_sender) + : ServerMediaSubsession(env), env(env), destPort(0), mod(mod), RTPPort(RTPPort), path_sender(path_sender) { + if (mod == NULL) + throw std::system_error(); +} + +UltragridRTSPVideoSubsession* UltragridRTSPVideoSubsession::createNew(UsageEnvironment& env, struct module *mod, int RTPPort) { + return new UltragridRTSPVideoSubsession(env, mod, RTPPort); +} + +UltragridRTSPVideoSubsession::UltragridRTSPVideoSubsession(UsageEnvironment& env, struct module *mod, int RTPPort) + : UltragridRTSPSubsessionCommon(env, mod, RTPPort, path_sender) {} + +UltragridRTSPAudioSubsession* UltragridRTSPAudioSubsession::createNew(UsageEnvironment& env, struct module *mod, int RTPPort, int sampleRate, int numOfChannels, audio_codec_t codec) { + return new UltragridRTSPAudioSubsession(env, mod, RTPPort, sampleRate, numOfChannels, codec); +} + +UltragridRTSPAudioSubsession::UltragridRTSPAudioSubsession(UsageEnvironment& env, struct module *mod, int RTPPort, int sampleRate, int numOfChannels, audio_codec_t codec) + : UltragridRTSPSubsessionCommon(env, mod, RTPPort, path_sender), sampleRate(sampleRate), numOfChannels(numOfChannels), codec(codec) {} + +char const* UltragridRTSPVideoSubsession::sdpLines(int addressFamily) { + // already created + if (SDPLines.size() != 0) + return SDPLines.c_str(); + + AddressString ipAddressStr(nullAddress(addressFamily)); + + SDPLines += "m=video " + std::to_string(RTPPort) + " RTP/AVP 96\r\n"; + SDPLines += std::string("c=IN ") + (addressFamily == AF_INET ? "IP4 " : "IP6 ") + std::string(ipAddressStr.val()) + "\r\n"; + SDPLines += "b=AS:5000\r\n"; + SDPLines += "a=rtcp:" + std::to_string(RTPPort + 1) + "\r\n"; + SDPLines += "a=rtpmap:96 H264/90000\r\n"; + SDPLines += "a=control:" + std::string(trackId()) + "\r\n"; + + return SDPLines.c_str(); +} + +char const* UltragridRTSPAudioSubsession::sdpLines(int addressFamily) { + // already created + if (SDPLines.size() != 0) + return SDPLines.c_str(); + + AddressString ipAddressStr(nullAddress(addressFamily)); + + std::string audioCodec; + audioCodec.append(codec == AC_MULAW ? "PCMU" : codec == AC_ALAW ? "PCMA" : "OPUS"); + + int RTPPayloadType = calculateRTPPayloadType(); + + SDPLines += "m=audio " + std::to_string(RTPPort) + " RTP/AVP " + std::to_string(RTPPayloadType) + "\r\n"; + SDPLines += std::string("c=IN ") + (addressFamily == AF_INET ? "IP4 " : "IP6 ") + std::string(ipAddressStr.val()) + "\r\n"; + SDPLines += "b=AS:384\r\n"; + SDPLines += "a=rtcp:" + std::to_string(RTPPort + 1) + "\r\n"; + SDPLines += "a=rtpmap:" + std::to_string(RTPPayloadType) + " " + std::move(audioCodec) + "/" + std::to_string(sampleRate) + "/" + std::to_string(numOfChannels) + "\r\n"; + SDPLines += "a=control:" + std::string(trackId()) + "\r\n"; + + return SDPLines.c_str(); +} + +int UltragridRTSPAudioSubsession::calculateRTPPayloadType() { + if (sampleRate != 8000 || numOfChannels != 1) + return 97; + + if (codec == AC_MULAW) + return 0; + if (codec == AC_ALAW) + return 8; + return 97; +} + +void UltragridRTSPSubsessionCommon::getStreamParameters( + MAYBE_UNUSED_ATTRIBUTE unsigned /* clientSessionId */, // in + MAYBE_UNUSED_ATTRIBUTE struct sockaddr_storage const& clientAddress, // in + MAYBE_UNUSED_ATTRIBUTE Port const& clientRTPPort, // in + MAYBE_UNUSED_ATTRIBUTE Port const& /* clientRTCPPort */, // in + MAYBE_UNUSED_ATTRIBUTE int /* tcpSocketNum */, // in (-1 means use UDP, not TCP) + MAYBE_UNUSED_ATTRIBUTE unsigned char /* rtpChannelId */, // in (used if TCP) + MAYBE_UNUSED_ATTRIBUTE unsigned char /* rtcpChannelId */, // in (used if TCP) + MAYBE_UNUSED_ATTRIBUTE TLSState* /* tlsState */, // in (used if TCP) + MAYBE_UNUSED_ATTRIBUTE struct sockaddr_storage& destinationAddress, // in out + MAYBE_UNUSED_ATTRIBUTE u_int8_t& /* destinationTTL */, // in out + MAYBE_UNUSED_ATTRIBUTE Boolean& /* isMulticast */, // out + MAYBE_UNUSED_ATTRIBUTE Port& serverRTPPort, // out + MAYBE_UNUSED_ATTRIBUTE Port& serverRTCPPort, // out + MAYBE_UNUSED_ATTRIBUTE void*& /* streamToken */ // out + ) { + + // out + destinationAddress = clientAddress; + serverRTPPort = Port(RTPPort); + serverRTCPPort = Port(RTPPort + 1); + + // in + destAddress = destinationAddress; + destPort = clientRTPPort; +} + +void UltragridRTSPSubsessionCommon::startStream( + MAYBE_UNUSED_ATTRIBUTE unsigned /* clientSessionId */, + MAYBE_UNUSED_ATTRIBUTE void* /* streamToken */, + MAYBE_UNUSED_ATTRIBUTE TaskFunc* /* rtcpRRHandler */, + MAYBE_UNUSED_ATTRIBUTE void* /* rtcpRRHandlerClientData */, + MAYBE_UNUSED_ATTRIBUTE unsigned short& /* rtpSeqNum */, + MAYBE_UNUSED_ATTRIBUTE unsigned& /* rtpTimestamp */, + MAYBE_UNUSED_ATTRIBUTE ServerRequestAlternativeByteHandler* /* serverRequestAlternativeByteHandler */, + MAYBE_UNUSED_ATTRIBUTE void* /* serverRequestAlternativeByteHandlerClientData */ + ) { + + if (addressIsNull(destAddress) || destPort.num() == 0) { + env << "[RTSP Server] Error: Failed to start (audio OR video) stream due to empty destination address\n"; + return; + } + + redirectStream(AddressString(destAddress).val(), destPort.num()); +} + +void UltragridRTSPSubsessionCommon::deleteStream(MAYBE_UNUSED_ATTRIBUTE unsigned /* clientSessionId */, MAYBE_UNUSED_ATTRIBUTE void*& /* streamToken */) { + destAddress = sockaddr_storage(); + destPort = Port(0); + + redirectStream("127.0.0.1", RTPPort); +} + +void UltragridRTSPSubsessionCommon::redirectStream(const char* destinationAddress, int destinationPort) { + char pathV[1024]; + memset(pathV, 0, sizeof(pathV)); + append_message_path(pathV, sizeof(pathV), path_sender); + struct response *resp = NULL; + // change destination port + struct msg_sender *msg1 = (struct msg_sender *) new_message(sizeof(struct msg_sender)); + msg1->tx_port = ntohs(destinationPort); + msg1->type = SENDER_MSG_CHANGE_PORT; + resp = send_message(mod, pathV, (struct message *) msg1); + free_response(resp); + + // change destination address + struct msg_sender *msg2 = (struct msg_sender *) new_message(sizeof(struct msg_sender)); + strncpy(msg2->receiver, destinationAddress, sizeof(msg2->receiver) - 1); + msg2->type = SENDER_MSG_CHANGE_RECEIVER; + resp = send_message(mod, pathV, (struct message *) msg2); + free_response(resp); +} + +#undef MAYBE_UNUSED_ATTRIBUTE diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh new file mode 100644 index 0000000000..fe4f7c4095 --- /dev/null +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -0,0 +1,182 @@ +/* + * FILE: rtsp/UltragridRTSPSubsession.hh + * AUTHORS: David Cassany + * Gerard Castillo + * Martin Pulec + * Jakub Kováč + * + * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya + * Copyright (c) 2010-2023 CESNET, z. s. p. o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the Fundació i2CAT, + * Internet I Innovació Digital a Catalunya. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University nor of the Institute may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/** + * Implement handling functions for RTSP methods + * + * @note for inspiration look in Live555 library + * liveMedia/include/OnDemandServerMediaSubsession.hh + * liveMedia/OnDemandServerMediaSubsession.cpp +*/ + +#ifndef BASIC_RTSP_SUBSESSION_HH +#define BASIC_RTSP_SUBSESSION_HH + +#ifdef __clang__ +#define MAYBE_UNUSED_ATTRIBUTE [[maybe_unused]] +#else +#define MAYBE_UNUSED_ATTRIBUTE // GCC complains if [[maybe_used]] is used there +#endif + +#include +#include +#include "audio/types.h" +#include "module.h" + +class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { +protected: + UltragridRTSPSubsessionCommon(UsageEnvironment& env, struct module *mod, int RTPPort, enum module_class *path_sender); + + /** + * @note called by Live555 when handling SETUP method + */ + virtual void getStreamParameters( + unsigned clientSessionId, // in + struct sockaddr_storage const& clientAddress, // in + Port const& clientRTPPort, // in + Port const& clientRTCPPort, // in + int tcpSocketNum, // in (-1 means use UDP, not TCP) + unsigned char rtpChannelId, // in (used if TCP) + unsigned char rtcpChannelId, // in (used if TCP) + TLSState* tlsState, // in (used if TCP) + struct sockaddr_storage& destinationAddress, // in out + u_int8_t& destinationTTL, // in out + Boolean& isMulticast, // out + Port& serverRTPPort, // out + Port& serverRTCPPort, // out + void*& streamToken // out + ); + + /** + * @note called by Live555 when handling PLAY method + */ + virtual void startStream( + unsigned clientSessionId, + void* streamToken, + TaskFunc* rtcpRRHandler, + void* rtcpRRHandlerClientData, + unsigned short& rtpSeqNum, + unsigned& rtpTimestamp, + ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, + void* serverRequestAlternativeByteHandlerClientData + ); + + /** + * @note called by Live555 when handling TEARDOWN method + */ + virtual void deleteStream(unsigned clientSessionId, void*& streamToken); + + /** + * none of the arguments are used in this implementaton of server, so the function does nothing + */ + virtual void getRTPSinkandRTCP( + MAYBE_UNUSED_ATTRIBUTE void* /* streamToken */, + MAYBE_UNUSED_ATTRIBUTE RTPSink *& /* rtpSink */, + MAYBE_UNUSED_ATTRIBUTE RTCPInstance *& /* rtcp */) {} + + /** + * tells UltraGrid (SENDER module) where (IP adress and port) to send media + */ + void redirectStream(const char* destinationAddress, int destinationPort); + + UsageEnvironment& env; + std::string SDPLines; + struct sockaddr_storage destAddress; + Port destPort; + + struct module *mod; + int RTPPort; + + enum module_class *path_sender; + const Boolean fReuseFirstSource = True; // tells Live555 that all clients use same source, eg. no pausing, seeking ... +}; + +class UltragridRTSPVideoSubsession: public UltragridRTSPSubsessionCommon { +public: + static UltragridRTSPVideoSubsession* createNew(UsageEnvironment& env, struct module *mod, int RTPPort); + UltragridRTSPVideoSubsession(UsageEnvironment& env, struct module *mod, int RTPPort); + + /** + * Generates media description according to SDP + * + * @note called by Live555 when handling DESCRIBE method + */ + virtual char const* sdpLines(int addressFamily); + +private: + enum module_class path_sender[2] = {MODULE_CLASS_SENDER, MODULE_CLASS_NONE}; // for communication with sender module +}; + +class UltragridRTSPAudioSubsession: public UltragridRTSPSubsessionCommon { +public: + static UltragridRTSPAudioSubsession* createNew(UsageEnvironment& env, struct module *mod, int RTPPort, int sampleRate, int numOfChannels, audio_codec_t codec); + UltragridRTSPAudioSubsession(UsageEnvironment& env, struct module *mod, int RTPPort, int sampleRate, int numOfChannels, audio_codec_t codec); + + /** + * Generates media description according to SDP + * + * @note called by Live555 when handling DESCRIBE method + */ + virtual char const* sdpLines(int addressFamily); + +private: + /** + * returns payload type according to RFC 3551 + */ + int calculateRTPPayloadType(); + + int sampleRate; + int numOfChannels; + audio_codec_t codec; + + enum module_class path_sender[3] = {MODULE_CLASS_AUDIO, MODULE_CLASS_SENDER, MODULE_CLASS_NONE}; // for communication with sender module +}; + +typedef UltragridRTSPSubsessionCommon BasicRTSPOnlySubsession; // kept for legacy maintanance + +#undef MAYBE_UNUSED_ATTRIBUTE + +#endif // BASIC_RTSP_SUBSESSION_HH diff --git a/src/rtsp/rtsp_utils.h b/src/rtsp/rtsp_utils.h index 253fa90264..5ee8037b3d 100644 --- a/src/rtsp/rtsp_utils.h +++ b/src/rtsp/rtsp_utils.h @@ -1,13 +1,59 @@ -#ifndef _RTSP_TYPES_HH -#define _RTSP_TYPES_HH +/* + * FILE: rtsp/rtsp_utils.h + * AUTHORS: David Cassany + * Gerard Castillo + * Martin Pulec + * Jakub Kováč + * + * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya + * Copyright (c) 2010-2023 CESNET, z. s. p. o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the Fundació i2CAT, + * Internet I Innovació Digital a Catalunya. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University nor of the Institute may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef RTSP_UTILS_H +#define RTSP_UTILS_H typedef enum { none, av, video, audio, - NUM_RTSP_FORMATS -}rtps_types_t; - + NUM_RTSP_MEDIA_TYPES +} rtsp_media_type_t; -#endif +#endif // RTSP_UTILS_H diff --git a/src/rtsp/c_basicRTSPOnlyServer.h b/src/rtsp/ultragrid_rtsp.cpp similarity index 59% rename from src/rtsp/c_basicRTSPOnlyServer.h rename to src/rtsp/ultragrid_rtsp.cpp index 8a9794e9aa..90a0878d40 100644 --- a/src/rtsp/c_basicRTSPOnlyServer.h +++ b/src/rtsp/ultragrid_rtsp.cpp @@ -1,9 +1,12 @@ /* - * FILE: rtsp/c_basicRTSPOnlyServer.h + * FILE: rtsp/ultragrid_rtsp.cpp * AUTHORS: David Cassany * Gerard Castillo + * Martin Pulec + * Jakub Kováč * * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya + * Copyright (c) 2010-2023 CESNET, z. s. p. o. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions @@ -41,50 +44,42 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef C_BASIC_RTSP_ONLY_SERVER_H -#define C_BASIC_RTSP_ONLY_SERVER_H -#endif -#ifdef HAVE_CONFIG_H -#include "config.h" -#include "config_unix.h" -#include "config_win32.h" -#endif // HAVE_CONFIG_H +#include "rtsp/ultragrid_rtsp.hh" +#include "rtsp/UltragridRTSPServer.hh" -#include -#include "control_socket.h" -#include "module.h" -#include "debug.h" -#include "rtsp/rtsp_utils.h" -#include "audio/types.h" +ultragrid_rtsp::ultragrid_rtsp(unsigned int rtsp_port, struct module* mod, rtsp_media_type_t media_type, audio_codec_t audio_codec, + int audio_sample_rate, int audio_channels, int rtp_video_port, int rtp_audio_port) + : thread_running(false) { + rtsp_server = std::make_unique(rtsp_port, mod, media_type, audio_codec, audio_sample_rate, audio_channels, rtp_video_port, rtp_audio_port); +} +ultragrid_rtsp::~ultragrid_rtsp() { + stop_server(); +} -#ifdef __cplusplus -#define EXTERNC extern "C" -#else -#define EXTERNC -#endif +int ultragrid_rtsp::start_server() { + if (thread_running) + return 1; + server_stop_flag = 0; -EXTERNC typedef struct rtsp_serv { - unsigned int port; - struct module *mod; - pthread_t server_th; - uint8_t watch; - uint8_t run; - rtps_types_t avType; - audio_codec_t audio_codec; - int audio_sample_rate; - int audio_channels; - int audio_bps; - int rtp_port; //server rtp port - int rtp_port_audio; -} rtsp_serv_t; + int ret; + ret = pthread_create(&server_thread, NULL, ultragrid_rtsp::server_runner, this); + thread_running = (ret == 0) ? true : false; + return ret; +} -EXTERNC int c_start_server(rtsp_serv_t* server); +void ultragrid_rtsp::stop_server() { + server_stop_flag = 1; -EXTERNC void c_stop_server(rtsp_serv_t* server); - -EXTERNC rtsp_serv_t* init_rtsp_server(unsigned int port, struct module *mod, rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio); - -#undef EXTERNC + if (thread_running) { + pthread_join(server_thread, NULL); + thread_running = false; + } +} +void* ultragrid_rtsp::server_runner(void* args) { + ultragrid_rtsp* server_instance = (ultragrid_rtsp*) args; + server_instance->rtsp_server->serverRunner(&server_instance->server_stop_flag); + return NULL; +} diff --git a/src/rtsp/c_basicRTSPOnlyServer.cpp b/src/rtsp/ultragrid_rtsp.hh similarity index 55% rename from src/rtsp/c_basicRTSPOnlyServer.cpp rename to src/rtsp/ultragrid_rtsp.hh index e16fe669c1..b99d4cd1d3 100644 --- a/src/rtsp/c_basicRTSPOnlyServer.cpp +++ b/src/rtsp/ultragrid_rtsp.hh @@ -1,9 +1,12 @@ /* - * FILE: rtsp/c_basicRTSPOnlyServer.cpp + * FILE: rtsp/ultragrid_rtsp.h * AUTHORS: David Cassany * Gerard Castillo + * Martin Pulec + * Jakub Kováč * * Copyright (c) 2005-2010 Fundació i2CAT, Internet I Innovació Digital a Catalunya + * Copyright (c) 2010-2023 CESNET, z. s. p. o. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions @@ -41,42 +44,54 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#include "rtsp/c_basicRTSPOnlyServer.h" -#include "rtsp/BasicRTSPOnlyServer.hh" -int c_start_server(rtsp_serv_t* server){ - int ret; - BasicRTSPOnlyServer *srv = BasicRTSPOnlyServer::initInstance(server->port, server->mod, server->avType, server->audio_codec, server->audio_sample_rate, server->audio_channels, server->audio_bps, server->rtp_port, server->rtp_port_audio); - srv->init_server(); - ret = pthread_create(&server->server_th, NULL, BasicRTSPOnlyServer::start_server, &server->watch); - if (ret == 0){ - server->run = TRUE; - } else { - server->run = FALSE; - } - return ret; -} +#ifndef ULTRAGRID_RTSP_HH +#define ULTRAGRID_RTSP_HH -rtsp_serv_t *init_rtsp_server(unsigned int port, struct module *mod, rtps_types_t avType, audio_codec_t audio_codec, int audio_sample_rate, int audio_channels, int audio_bps, int rtp_port, int rtp_port_audio){ - rtsp_serv_t *server = (rtsp_serv_t*) malloc(sizeof(rtsp_serv_t)); - server->port = port; - server->mod = mod; - server->watch = 0; - server->run = FALSE; - server->avType = avType; - server->audio_codec = audio_codec; - server->audio_sample_rate = audio_sample_rate; - server->audio_channels = audio_channels; - server->audio_bps = audio_bps; - server->rtp_port = rtp_port; - server->rtp_port_audio = rtp_port_audio; - return server; -} +#include +#include "rtsp/rtsp_utils.h" +#include "audio/types.h" +#include "module.h" -void c_stop_server(rtsp_serv_t* server){ - server->watch = 1; - if (server->run){ - pthread_join(server->server_th, NULL); - } -} +class UltragridRTSPServer; +class ultragrid_rtsp { +public: + /** + * @param rtsp_port The caller is responsible for ensuring the port is available. + * If set as 0, the server will use the default value. + */ + ultragrid_rtsp(unsigned int rtsp_port, struct module* mod, rtsp_media_type_t media_type, audio_codec_t audio_codec, + int audio_sample_rate, int audio_channels, int rtp_video_port, int rtp_audio_port); + /** + * Stops server and frees any allocated memory + */ + ~ultragrid_rtsp(); + + /** + * Copy constructor and copy assignment operator do not make sense in this context + */ + ultragrid_rtsp(const ultragrid_rtsp&) = delete; + ultragrid_rtsp& operator=(const ultragrid_rtsp&) = delete; + + /** + * Start server in new thread + * + * @retval 0 New thread created and server started successfully + */ + int start_server(); + /** + * @note can be started again by calling start_server + */ + void stop_server(); + +private: + static void* server_runner(void* args); + + pthread_t server_thread; + bool thread_running; + char server_stop_flag; // 0 server can run, 1 server should stop + std::unique_ptr rtsp_server; // pointer to avoid name clashes with live555 +}; + +#endif // ULTRAGRID_RTSP_HH diff --git a/src/video_capture/rtsp.c b/src/video_capture/rtsp.c index f11f6f9254..5751054246 100644 --- a/src/video_capture/rtsp.c +++ b/src/video_capture/rtsp.c @@ -234,7 +234,7 @@ struct audio_rtsp_state { struct rtsp_state { CURL *curl; char uri[1024]; - rtps_types_t avType; + rtsp_media_type_t media_type; const char *addr; char *sdp; @@ -483,7 +483,7 @@ vidcap_rtsp_init(struct vidcap_params *params, void **state) { int len = -1; char *save_ptr = NULL; - s->avType = none; //-1 none, 0 a&v, 1 v, 2 a + s->media_type = none; //-1 none, 0 a&v, 1 v, 2 a s->addr = "127.0.0.1"; s->vrtsp_state.device = NULL; diff --git a/src/video_rxtx/h264_rtp.cpp b/src/video_rxtx/h264_rtp.cpp index 3bd003c941..c83f2a07d7 100644 --- a/src/video_rxtx/h264_rtp.cpp +++ b/src/video_rxtx/h264_rtp.cpp @@ -7,7 +7,7 @@ */ /* * Copyright (c) 2013-2014 Fundació i2CAT, Internet I Innovació Digital a Catalunya - * Copyright (c) 2013-2024 CESNET, z. s. p. o. + * Copyright (c) 2013-2023 CESNET, z. s. p. o. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,48 +46,47 @@ * version from 7th Aug 2015). */ -#include -#include -#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif // HAVE_CONFIG_H #include "compat/misc.h" #include "debug.h" #include "host.h" #include "lib_common.h" -#include "rtp/rtp.h" -#include "rtp/rtpenc_h264.h" #include "transmit.h" #include "tv.h" +#include "rtp/rtp.h" +#include "rtp/rtpenc_h264.h" #include "utils/color_out.h" -#include "video.h" #include "video_rxtx.hpp" #include "video_rxtx/h264_rtp.hpp" +#include "video.h" -#define MOD_NAME "[vrxtx/h264_rtp] " - -using std::shared_ptr; +using namespace std; h264_rtp_video_rxtx::h264_rtp_video_rxtx(std::map const ¶ms, int rtsp_port) : rtp_video_rxtx(params) -{ - m_rtsp_server = init_rtsp_server(rtsp_port, + #ifdef HAVE_RTSP_SERVER + , m_rtsp_server(rtsp_port, static_cast(params.at("parent").ptr), - static_cast(params.at("avType").l), + static_cast(params.at("media_type").l), static_cast(params.at("audio_codec").l), params.at("audio_sample_rate").i, params.at("audio_channels").i, - params.at("audio_bps").i, params.at("rx_port").i, params.at("a_rx_port").i); - c_start_server(m_rtsp_server); + params.at("rx_port").i, params.at("a_rx_port").i) + #endif // HAVE_RTSP_SERVER +{ +#ifdef HAVE_RTSP_SERVER + m_rtsp_server.start_server(); +#endif // HAVE_RTSP_SERVER } void h264_rtp_video_rxtx::send_frame(shared_ptr tx_frame) noexcept { - if (tx_frame->color_spec != H264) { - MSG(ERROR, - "codecs other than H.264 currently not supported, got %s\n", - get_codec_name(tx_frame->color_spec)); - } tx_send_h264(m_tx, tx_frame.get(), m_network_device); if ((m_rxtx_mode & MODE_RECEIVER) == 0) { // send RTCP (receiver thread would otherwise do this time_ns_t curr_time = get_time_in_ns(); @@ -105,13 +104,6 @@ h264_rtp_video_rxtx::send_frame(shared_ptr tx_frame) noexcept h264_rtp_video_rxtx::~h264_rtp_video_rxtx() { - free(m_rtsp_server); -} - -void h264_rtp_video_rxtx::join() -{ - c_stop_server(m_rtsp_server); - video_rxtx::join(); } static void rtps_server_usage(){ @@ -150,13 +142,14 @@ static video_rxtx *create_video_rxtx_h264_std(std::map con if (strlen(rtsp_port_str) == 0) { rtsp_port = 0; } else { - if (strcmp(rtsp_port_str, "help") == 0) { + if (!strcmp(rtsp_port_str, "help")) { +#ifdef HAVE_RTSP_SERVER rtps_server_usage(); - return nullptr; - } - rtsp_port = get_rtsp_server_port(rtsp_port_str); - if (rtsp_port == -1) { - return nullptr; +#endif + return 0; + } else { + rtsp_port = get_rtsp_server_port(rtsp_port_str); + if (rtsp_port == -1) return 0; } } return new h264_rtp_video_rxtx(params, rtsp_port); diff --git a/src/video_rxtx/h264_rtp.hpp b/src/video_rxtx/h264_rtp.hpp index 41118d8334..ee1a789019 100644 --- a/src/video_rxtx/h264_rtp.hpp +++ b/src/video_rxtx/h264_rtp.hpp @@ -42,7 +42,7 @@ #ifndef VIDEO_RXTX_H264_RTP_H_ #define VIDEO_RXTX_H264_RTP_H_ -#include "rtsp/c_basicRTSPOnlyServer.h" +#include "rtsp/ultragrid_rtsp.hh" #include "video_rxtx.hpp" #include "video_rxtx/rtp.hpp" @@ -56,7 +56,9 @@ class h264_rtp_video_rxtx : public rtp_video_rxtx { virtual void *(*get_receiver_thread() noexcept)(void *arg) override { return NULL; } - rtsp_serv_t *m_rtsp_server; + #ifdef HAVE_RTSP_SERVER + ultragrid_rtsp m_rtsp_server; + #endif // HAVE_RTSP_SERVER }; #endif // VIDEO_RXTX_H264_RTP_H_