From fb518521fb88a90c6ffb45aa7d89b397b8c6feb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 14:03:10 +0200 Subject: [PATCH 01/31] step 0: make room for the rebuilt implementation - so that code can be established upon existing example in Live555. - Result will look simmilar to this, but will be rebuild as series of logical steps --- src/rtsp/BasicRTSPOnlyServer.cpp | 162 ------------- src/rtsp/BasicRTSPOnlyServer.hh | 86 ------- src/rtsp/BasicRTSPOnlySubsession.cpp | 345 --------------------------- src/rtsp/BasicRTSPOnlySubsession.hh | 154 ------------ src/rtsp/c_basicRTSPOnlyServer.cpp | 82 ------- src/rtsp/c_basicRTSPOnlyServer.h | 90 ------- src/rtsp/rtsp_utils.h | 13 - 7 files changed, 932 deletions(-) delete mode 100644 src/rtsp/BasicRTSPOnlyServer.cpp delete mode 100644 src/rtsp/BasicRTSPOnlyServer.hh delete mode 100644 src/rtsp/BasicRTSPOnlySubsession.cpp delete mode 100644 src/rtsp/BasicRTSPOnlySubsession.hh delete mode 100644 src/rtsp/c_basicRTSPOnlyServer.cpp delete mode 100644 src/rtsp/c_basicRTSPOnlyServer.h delete mode 100644 src/rtsp/rtsp_utils.h 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/BasicRTSPOnlyServer.hh b/src/rtsp/BasicRTSPOnlyServer.hh deleted file mode 100644 index a437eaacc6..0000000000 --- a/src/rtsp/BasicRTSPOnlyServer.hh +++ /dev/null @@ -1,86 +0,0 @@ -/* - * FILE: rtsp/BasicRTSPOnlyServer.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_SERVER_HH -#define _BASIC_RTSP_ONLY_SERVER_HH - -#include -#include -#include "rtsp/rtsp_utils.h" -#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); - -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(); - - int init_server(); - - static void *start_server(void *args); - - int update_server(); - -private: - - 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 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/c_basicRTSPOnlyServer.cpp b/src/rtsp/c_basicRTSPOnlyServer.cpp deleted file mode 100644 index e16fe669c1..0000000000 --- a/src/rtsp/c_basicRTSPOnlyServer.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * FILE: rtsp/c_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/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; -} - -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; -} - -void c_stop_server(rtsp_serv_t* server){ - server->watch = 1; - if (server->run){ - pthread_join(server->server_th, NULL); - } -} - diff --git a/src/rtsp/c_basicRTSPOnlyServer.h b/src/rtsp/c_basicRTSPOnlyServer.h deleted file mode 100644 index 8a9794e9aa..0000000000 --- a/src/rtsp/c_basicRTSPOnlyServer.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * FILE: rtsp/c_basicRTSPOnlyServer.h - * 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 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 -#include "control_socket.h" -#include "module.h" -#include "debug.h" -#include "rtsp/rtsp_utils.h" -#include "audio/types.h" - - -#ifdef __cplusplus -#define EXTERNC extern "C" -#else -#define EXTERNC -#endif - -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; - -EXTERNC int c_start_server(rtsp_serv_t* server); - -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 - diff --git a/src/rtsp/rtsp_utils.h b/src/rtsp/rtsp_utils.h deleted file mode 100644 index 253fa90264..0000000000 --- a/src/rtsp/rtsp_utils.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _RTSP_TYPES_HH -#define _RTSP_TYPES_HH - -typedef enum { - none, - av, - video, - audio, - NUM_RTSP_FORMATS -}rtps_types_t; - - -#endif From cac2c9a36c35599fabef54cf113f5bdb869ab94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 15:16:16 +0200 Subject: [PATCH 02/31] step 1: import example from Live555 library - that will be base of rtsp server - file originaly located in Live555 library source code at testProgs/testOnDemandRTSPServer.cpp --- src/rtsp/testOnDemandRTSPServer.cpp | 474 ++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 src/rtsp/testOnDemandRTSPServer.cpp diff --git a/src/rtsp/testOnDemandRTSPServer.cpp b/src/rtsp/testOnDemandRTSPServer.cpp new file mode 100644 index 0000000000..3696a77681 --- /dev/null +++ b/src/rtsp/testOnDemandRTSPServer.cpp @@ -0,0 +1,474 @@ +/********** +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 +// A test program that demonstrates how to stream - via unicast RTP +// - various kinds of file on demand, using a built-in RTSP server. +// main program + +#include "liveMedia.hh" + +#include "BasicUsageEnvironment.hh" +#include "announceURL.hh" + +UsageEnvironment* env; + +// To make the second and subsequent client for each stream reuse the same +// input stream as the first client (rather than playing the file from the +// start for each client), change the following "False" to "True": +Boolean reuseFirstSource = False; + +// To stream *only* MPEG-1 or 2 video "I" frames +// (e.g., to reduce network bandwidth), +// change the following "False" to "True": +Boolean iFramesOnly = False; + +static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, + char const* streamName, char const* inputFileName); // forward + +static char newDemuxWatchVariable; + +static MatroskaFileServerDemux* matroskaDemux; +static void onMatroskaDemuxCreation(MatroskaFileServerDemux* newDemux, void* /*clientData*/) { + matroskaDemux = newDemux; + newDemuxWatchVariable = 1; +} + +static OggFileServerDemux* oggDemux; +static void onOggDemuxCreation(OggFileServerDemux* newDemux, void* /*clientData*/) { + oggDemux = newDemux; + newDemuxWatchVariable = 1; +} + +int main(int argc, char** argv) { + // 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 + + // Create the RTSP server: +#ifdef SERVER_USE_TLS + // Serve RTSPS: RTSP over a TLS connection: + RTSPServer* rtspServer = RTSPServer::createNew(*env, 322, authDB); +#else + // Serve regular RTSP (over a TCP connection): + RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB); +#endif + if (rtspServer == NULL) { + *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; + exit(1); + } +#ifdef SERVER_USE_TLS +#ifndef STREAM_USING_SRTP +#define STREAM_USING_SRTP True +#endif + rtspServer->setTLSState(PATHNAME_TO_CERTIFICATE_FILE, PATHNAME_TO_PRIVATE_KEY_FILE, + STREAM_USING_SRTP); +#endif + + char const* descriptionString + = "Session streamed by \"testOnDemandRTSPServer\""; + + // Set up each of the possible streams that can be served by the + // RTSP server. Each such stream is implemented using a + // "ServerMediaSession" object, plus one or more + // "ServerMediaSubsession" objects for each audio/video substream. + + // A MPEG-4 video elementary stream: + { + char const* streamName = "mpeg4ESVideoTest"; + char const* inputFileName = "test.m4e"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(MPEG4VideoFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A H.264 video elementary stream: + { + char const* streamName = "h264ESVideoTest"; + char const* inputFileName = "test.264"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(H264VideoFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A H.265 video elementary stream: + { + char const* streamName = "h265ESVideoTest"; + char const* inputFileName = "test.265"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(H265VideoFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A MPEG-1 or 2 audio+video program stream: + { + char const* streamName = "mpeg1or2AudioVideoTest"; + char const* inputFileName = "test.mpg"; + // NOTE: This *must* be a Program Stream; not an Elementary Stream + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + MPEG1or2FileServerDemux* demux + = MPEG1or2FileServerDemux::createNew(*env, inputFileName, reuseFirstSource); + sms->addSubsession(demux->newVideoServerMediaSubsession(iFramesOnly)); + sms->addSubsession(demux->newAudioServerMediaSubsession()); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A MPEG-1 or 2 video elementary stream: + { + char const* streamName = "mpeg1or2ESVideoTest"; + char const* inputFileName = "testv.mpg"; + // NOTE: This *must* be a Video Elementary Stream; not a Program Stream + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(MPEG1or2VideoFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource, iFramesOnly)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A MP3 audio stream (actually, any MPEG-1 or 2 audio file will work): + // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following: +//#define STREAM_USING_ADUS 1 + // To also reorder ADUs before streaming, uncomment the following: +//#define INTERLEAVE_ADUS 1 + // (For more information about ADUs and interleaving, + // see ) + { + char const* streamName = "mp3AudioTest"; + char const* inputFileName = "test.mp3"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + Boolean useADUs = False; + Interleaving* interleaving = NULL; +#ifdef STREAM_USING_ADUS + useADUs = True; +#ifdef INTERLEAVE_ADUS + unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own... + unsigned const interleaveCycleSize + = (sizeof interleaveCycle)/(sizeof (unsigned char)); + interleaving = new Interleaving(interleaveCycleSize, interleaveCycle); +#endif +#endif + sms->addSubsession(MP3AudioFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource, + useADUs, interleaving)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A WAV audio stream: + { + char const* streamName = "wavAudioTest"; + char const* inputFileName = "test.wav"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + // To convert 16-bit PCM data to 8-bit u-law, prior to streaming, + // change the following to True: + Boolean convertToULaw = False; + sms->addSubsession(WAVAudioFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource, convertToULaw)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // An AMR audio stream: + { + char const* streamName = "amrAudioTest"; + char const* inputFileName = "test.amr"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(AMRAudioFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A 'VOB' file (e.g., from an unencrypted DVD): + { + char const* streamName = "vobTest"; + char const* inputFileName = "test.vob"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + // Note: VOB files are MPEG-2 Program Stream files, but using AC-3 audio + MPEG1or2FileServerDemux* demux + = MPEG1or2FileServerDemux::createNew(*env, inputFileName, reuseFirstSource); + sms->addSubsession(demux->newVideoServerMediaSubsession(iFramesOnly)); + sms->addSubsession(demux->newAC3AudioServerMediaSubsession()); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A MPEG-2 Transport Stream: + { + char const* streamName = "mpeg2TransportStreamTest"; + char const* inputFileName = "test.ts"; + char const* indexFileName = "test.tsx"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(MPEG2TransportFileServerMediaSubsession + ::createNew(*env, inputFileName, indexFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // An AAC audio stream (ADTS-format file): + { + char const* streamName = "aacAudioTest"; + char const* inputFileName = "test.aac"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(ADTSAudioFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A DV video stream: + { + // First, make sure that the RTPSinks' buffers will be large enough to handle the huge size of DV frames (as big as 288000). + OutPacketBuffer::maxSize = 300000; + + char const* streamName = "dvVideoTest"; + char const* inputFileName = "test.dv"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(DVVideoFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A AC3 video elementary stream: + { + char const* streamName = "ac3AudioTest"; + char const* inputFileName = "test.ac3"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + + sms->addSubsession(AC3AudioFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A Matroska ('.mkv') file, with video+audio+subtitle streams: + { + char const* streamName = "matroskaFileTest"; + char const* inputFileName = "test.mkv"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + + newDemuxWatchVariable = 0; + MatroskaFileServerDemux::createNew(*env, inputFileName, onMatroskaDemuxCreation, NULL); + env->taskScheduler().doEventLoop(&newDemuxWatchVariable); + + Boolean sessionHasTracks = False; + ServerMediaSubsession* smss; + while ((smss = matroskaDemux->newServerMediaSubsession()) != NULL) { + sms->addSubsession(smss); + sessionHasTracks = True; + } + if (sessionHasTracks) { + rtspServer->addServerMediaSession(sms); + } + // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A WebM ('.webm') file, with video(VP8)+audio(Vorbis) streams: + // (Note: ".webm' files are special types of Matroska files, so we use the same code as the Matroska ('.mkv') file code above.) + { + char const* streamName = "webmFileTest"; + char const* inputFileName = "test.webm"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + + newDemuxWatchVariable = 0; + MatroskaFileServerDemux::createNew(*env, inputFileName, onMatroskaDemuxCreation, NULL); + env->taskScheduler().doEventLoop(&newDemuxWatchVariable); + + Boolean sessionHasTracks = False; + ServerMediaSubsession* smss; + while ((smss = matroskaDemux->newServerMediaSubsession()) != NULL) { + sms->addSubsession(smss); + sessionHasTracks = True; + } + if (sessionHasTracks) { + rtspServer->addServerMediaSession(sms); + } + // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // An Ogg ('.ogg') file, with video and/or audio streams: + { + char const* streamName = "oggFileTest"; + char const* inputFileName = "test.ogg"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + + newDemuxWatchVariable = 0; + OggFileServerDemux::createNew(*env, inputFileName, onOggDemuxCreation, NULL); + env->taskScheduler().doEventLoop(&newDemuxWatchVariable); + + Boolean sessionHasTracks = False; + ServerMediaSubsession* smss; + while ((smss = oggDemux->newServerMediaSubsession()) != NULL) { + sms->addSubsession(smss); + sessionHasTracks = True; + } + if (sessionHasTracks) { + rtspServer->addServerMediaSession(sms); + } + // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // An Opus ('.opus') audio file: + // (Note: ".opus' files are special types of Ogg files, so we use the same code as the Ogg ('.ogg') file code above.) + { + char const* streamName = "opusFileTest"; + char const* inputFileName = "test.opus"; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + + newDemuxWatchVariable = 0; + OggFileServerDemux::createNew(*env, inputFileName, onOggDemuxCreation, NULL); + env->taskScheduler().doEventLoop(&newDemuxWatchVariable); + + Boolean sessionHasTracks = False; + ServerMediaSubsession* smss; + while ((smss = oggDemux->newServerMediaSubsession()) != NULL) { + sms->addSubsession(smss); + sessionHasTracks = True; + } + if (sessionHasTracks) { + rtspServer->addServerMediaSession(sms); + } + // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + // A MPEG-2 Transport Stream, coming from a live UDP (raw-UDP or RTP/UDP) source: + { + char const* streamName = "mpeg2TransportStreamFromUDPSourceTest"; + char const* inputAddressStr = "239.255.42.42"; + // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application. + // (Note: If the input UDP source is unicast rather than multicast, then change this to NULL.) + portNumBits const inputPortNum = 1234; + // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application. + Boolean const inputStreamIsRawUDP = False; + ServerMediaSession* sms + = ServerMediaSession::createNew(*env, streamName, streamName, + descriptionString); + sms->addSubsession(MPEG2TransportUDPServerMediaSubsession + ::createNew(*env, inputAddressStr, inputPortNum, inputStreamIsRawUDP)); + rtspServer->addServerMediaSession(sms); + + *env << "\n\"" << streamName << "\" stream, from a UDP Transport Stream input source \n\t("; + if (inputAddressStr != NULL) { + *env << "IP multicast address " << inputAddressStr << ","; + } else { + *env << "unicast;"; + } + *env << " port " << inputPortNum << ")\n"; + announceURL(rtspServer, sms); + } + + // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling. + // Try first with the default HTTP port (80), and then with the alternative HTTP + // port numbers (8000 and 8080). + +#ifdef SERVER_USE_TLS + // (Attempt to) use the default HTTPS port (443) instead: + char const* httpProtocolStr = "HTTPS"; + if (rtspServer->setUpTunnelingOverHTTP(443)) { +#else + char const* httpProtocolStr = "HTTP"; + if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) { +#endif + *env << "\n(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-" << httpProtocolStr << " tunneling.)\n"; + } else { + *env << "\n(RTSP-over-" << httpProtocolStr << " tunneling is not available.)\n"; + } + + env->taskScheduler().doEventLoop(); // does not return + + return 0; // only to prevent compiler warning +} + +static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, + char const* streamName, char const* inputFileName) { + UsageEnvironment& env = rtspServer->envir(); + + env << "\n\"" << streamName << "\" stream, from the file \"" + << inputFileName << "\"\n"; + announceURL(rtspServer, sms); +} From d36678f180856e3a293b6c0e9d13e5075e6bde95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 15:50:39 +0200 Subject: [PATCH 03/31] step 1: rename file and add UG copyright copyright notice was added from original file BasicRTSPOnlyServer.cpp --- ...RTSPServer.cpp => UltragridRTSPServer.cpp} | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) rename src/rtsp/{testOnDemandRTSPServer.cpp => UltragridRTSPServer.cpp} (88%) diff --git a/src/rtsp/testOnDemandRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp similarity index 88% rename from src/rtsp/testOnDemandRTSPServer.cpp rename to src/rtsp/UltragridRTSPServer.cpp index 3696a77681..929a1aaeff 100644 --- a/src/rtsp/testOnDemandRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -1,3 +1,53 @@ +/* + * 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 +*/ /********** 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 @@ -14,9 +64,6 @@ 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 -// A test program that demonstrates how to stream - via unicast RTP -// - various kinds of file on demand, using a built-in RTSP server. -// main program #include "liveMedia.hh" From 3820168b6a20f964cca8ecf5c8bddd7684e06681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 16:01:39 +0200 Subject: [PATCH 04/31] step 1: remove http(s) tunneling and TLS these features are not used needed by UltraGrid --- src/rtsp/UltragridRTSPServer.cpp | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index 929a1aaeff..6bb4b9cc80 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -114,24 +114,11 @@ int main(int argc, char** argv) { #endif // Create the RTSP server: -#ifdef SERVER_USE_TLS - // Serve RTSPS: RTSP over a TLS connection: - RTSPServer* rtspServer = RTSPServer::createNew(*env, 322, authDB); -#else - // Serve regular RTSP (over a TCP connection): RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB); -#endif if (rtspServer == NULL) { *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; exit(1); } -#ifdef SERVER_USE_TLS -#ifndef STREAM_USING_SRTP -#define STREAM_USING_SRTP True -#endif - rtspServer->setTLSState(PATHNAME_TO_CERTIFICATE_FILE, PATHNAME_TO_PRIVATE_KEY_FILE, - STREAM_USING_SRTP); -#endif char const* descriptionString = "Session streamed by \"testOnDemandRTSPServer\""; @@ -489,23 +476,6 @@ int main(int argc, char** argv) { announceURL(rtspServer, sms); } - // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling. - // Try first with the default HTTP port (80), and then with the alternative HTTP - // port numbers (8000 and 8080). - -#ifdef SERVER_USE_TLS - // (Attempt to) use the default HTTPS port (443) instead: - char const* httpProtocolStr = "HTTPS"; - if (rtspServer->setUpTunnelingOverHTTP(443)) { -#else - char const* httpProtocolStr = "HTTP"; - if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) { -#endif - *env << "\n(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-" << httpProtocolStr << " tunneling.)\n"; - } else { - *env << "\n(RTSP-over-" << httpProtocolStr << " tunneling is not available.)\n"; - } - env->taskScheduler().doEventLoop(); // does not return return 0; // only to prevent compiler warning From ba1e3f478c71877845feb654b15e162dd4c87255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 16:04:57 +0200 Subject: [PATCH 05/31] step 1: drop unused media formats, keep MPEG-4 MPEG-4 video is not deleted because it can serve as example of handling subsessions --- src/rtsp/UltragridRTSPServer.cpp | 353 ------------------------------- 1 file changed, 353 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index 6bb4b9cc80..1beaf49a78 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -77,28 +77,9 @@ UsageEnvironment* env; // start for each client), change the following "False" to "True": Boolean reuseFirstSource = False; -// To stream *only* MPEG-1 or 2 video "I" frames -// (e.g., to reduce network bandwidth), -// change the following "False" to "True": -Boolean iFramesOnly = False; - static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, char const* streamName, char const* inputFileName); // forward -static char newDemuxWatchVariable; - -static MatroskaFileServerDemux* matroskaDemux; -static void onMatroskaDemuxCreation(MatroskaFileServerDemux* newDemux, void* /*clientData*/) { - matroskaDemux = newDemux; - newDemuxWatchVariable = 1; -} - -static OggFileServerDemux* oggDemux; -static void onOggDemuxCreation(OggFileServerDemux* newDemux, void* /*clientData*/) { - oggDemux = newDemux; - newDemuxWatchVariable = 1; -} - int main(int argc, char** argv) { // Begin by setting up our usage environment: TaskScheduler* scheduler = BasicTaskScheduler::createNew(); @@ -142,340 +123,6 @@ int main(int argc, char** argv) { announceStream(rtspServer, sms, streamName, inputFileName); } - // A H.264 video elementary stream: - { - char const* streamName = "h264ESVideoTest"; - char const* inputFileName = "test.264"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(H264VideoFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A H.265 video elementary stream: - { - char const* streamName = "h265ESVideoTest"; - char const* inputFileName = "test.265"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(H265VideoFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A MPEG-1 or 2 audio+video program stream: - { - char const* streamName = "mpeg1or2AudioVideoTest"; - char const* inputFileName = "test.mpg"; - // NOTE: This *must* be a Program Stream; not an Elementary Stream - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - MPEG1or2FileServerDemux* demux - = MPEG1or2FileServerDemux::createNew(*env, inputFileName, reuseFirstSource); - sms->addSubsession(demux->newVideoServerMediaSubsession(iFramesOnly)); - sms->addSubsession(demux->newAudioServerMediaSubsession()); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A MPEG-1 or 2 video elementary stream: - { - char const* streamName = "mpeg1or2ESVideoTest"; - char const* inputFileName = "testv.mpg"; - // NOTE: This *must* be a Video Elementary Stream; not a Program Stream - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(MPEG1or2VideoFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource, iFramesOnly)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A MP3 audio stream (actually, any MPEG-1 or 2 audio file will work): - // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following: -//#define STREAM_USING_ADUS 1 - // To also reorder ADUs before streaming, uncomment the following: -//#define INTERLEAVE_ADUS 1 - // (For more information about ADUs and interleaving, - // see ) - { - char const* streamName = "mp3AudioTest"; - char const* inputFileName = "test.mp3"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - Boolean useADUs = False; - Interleaving* interleaving = NULL; -#ifdef STREAM_USING_ADUS - useADUs = True; -#ifdef INTERLEAVE_ADUS - unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own... - unsigned const interleaveCycleSize - = (sizeof interleaveCycle)/(sizeof (unsigned char)); - interleaving = new Interleaving(interleaveCycleSize, interleaveCycle); -#endif -#endif - sms->addSubsession(MP3AudioFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource, - useADUs, interleaving)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A WAV audio stream: - { - char const* streamName = "wavAudioTest"; - char const* inputFileName = "test.wav"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - // To convert 16-bit PCM data to 8-bit u-law, prior to streaming, - // change the following to True: - Boolean convertToULaw = False; - sms->addSubsession(WAVAudioFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource, convertToULaw)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // An AMR audio stream: - { - char const* streamName = "amrAudioTest"; - char const* inputFileName = "test.amr"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(AMRAudioFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A 'VOB' file (e.g., from an unencrypted DVD): - { - char const* streamName = "vobTest"; - char const* inputFileName = "test.vob"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - // Note: VOB files are MPEG-2 Program Stream files, but using AC-3 audio - MPEG1or2FileServerDemux* demux - = MPEG1or2FileServerDemux::createNew(*env, inputFileName, reuseFirstSource); - sms->addSubsession(demux->newVideoServerMediaSubsession(iFramesOnly)); - sms->addSubsession(demux->newAC3AudioServerMediaSubsession()); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A MPEG-2 Transport Stream: - { - char const* streamName = "mpeg2TransportStreamTest"; - char const* inputFileName = "test.ts"; - char const* indexFileName = "test.tsx"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(MPEG2TransportFileServerMediaSubsession - ::createNew(*env, inputFileName, indexFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // An AAC audio stream (ADTS-format file): - { - char const* streamName = "aacAudioTest"; - char const* inputFileName = "test.aac"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(ADTSAudioFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A DV video stream: - { - // First, make sure that the RTPSinks' buffers will be large enough to handle the huge size of DV frames (as big as 288000). - OutPacketBuffer::maxSize = 300000; - - char const* streamName = "dvVideoTest"; - char const* inputFileName = "test.dv"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(DVVideoFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A AC3 video elementary stream: - { - char const* streamName = "ac3AudioTest"; - char const* inputFileName = "test.ac3"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - - sms->addSubsession(AC3AudioFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A Matroska ('.mkv') file, with video+audio+subtitle streams: - { - char const* streamName = "matroskaFileTest"; - char const* inputFileName = "test.mkv"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - - newDemuxWatchVariable = 0; - MatroskaFileServerDemux::createNew(*env, inputFileName, onMatroskaDemuxCreation, NULL); - env->taskScheduler().doEventLoop(&newDemuxWatchVariable); - - Boolean sessionHasTracks = False; - ServerMediaSubsession* smss; - while ((smss = matroskaDemux->newServerMediaSubsession()) != NULL) { - sms->addSubsession(smss); - sessionHasTracks = True; - } - if (sessionHasTracks) { - rtspServer->addServerMediaSession(sms); - } - // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A WebM ('.webm') file, with video(VP8)+audio(Vorbis) streams: - // (Note: ".webm' files are special types of Matroska files, so we use the same code as the Matroska ('.mkv') file code above.) - { - char const* streamName = "webmFileTest"; - char const* inputFileName = "test.webm"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - - newDemuxWatchVariable = 0; - MatroskaFileServerDemux::createNew(*env, inputFileName, onMatroskaDemuxCreation, NULL); - env->taskScheduler().doEventLoop(&newDemuxWatchVariable); - - Boolean sessionHasTracks = False; - ServerMediaSubsession* smss; - while ((smss = matroskaDemux->newServerMediaSubsession()) != NULL) { - sms->addSubsession(smss); - sessionHasTracks = True; - } - if (sessionHasTracks) { - rtspServer->addServerMediaSession(sms); - } - // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // An Ogg ('.ogg') file, with video and/or audio streams: - { - char const* streamName = "oggFileTest"; - char const* inputFileName = "test.ogg"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - - newDemuxWatchVariable = 0; - OggFileServerDemux::createNew(*env, inputFileName, onOggDemuxCreation, NULL); - env->taskScheduler().doEventLoop(&newDemuxWatchVariable); - - Boolean sessionHasTracks = False; - ServerMediaSubsession* smss; - while ((smss = oggDemux->newServerMediaSubsession()) != NULL) { - sms->addSubsession(smss); - sessionHasTracks = True; - } - if (sessionHasTracks) { - rtspServer->addServerMediaSession(sms); - } - // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // An Opus ('.opus') audio file: - // (Note: ".opus' files are special types of Ogg files, so we use the same code as the Ogg ('.ogg') file code above.) - { - char const* streamName = "opusFileTest"; - char const* inputFileName = "test.opus"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - - newDemuxWatchVariable = 0; - OggFileServerDemux::createNew(*env, inputFileName, onOggDemuxCreation, NULL); - env->taskScheduler().doEventLoop(&newDemuxWatchVariable); - - Boolean sessionHasTracks = False; - ServerMediaSubsession* smss; - while ((smss = oggDemux->newServerMediaSubsession()) != NULL) { - sms->addSubsession(smss); - sessionHasTracks = True; - } - if (sessionHasTracks) { - rtspServer->addServerMediaSession(sms); - } - // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server. - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - // A MPEG-2 Transport Stream, coming from a live UDP (raw-UDP or RTP/UDP) source: - { - char const* streamName = "mpeg2TransportStreamFromUDPSourceTest"; - char const* inputAddressStr = "239.255.42.42"; - // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application. - // (Note: If the input UDP source is unicast rather than multicast, then change this to NULL.) - portNumBits const inputPortNum = 1234; - // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application. - Boolean const inputStreamIsRawUDP = False; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(MPEG2TransportUDPServerMediaSubsession - ::createNew(*env, inputAddressStr, inputPortNum, inputStreamIsRawUDP)); - rtspServer->addServerMediaSession(sms); - - *env << "\n\"" << streamName << "\" stream, from a UDP Transport Stream input source \n\t("; - if (inputAddressStr != NULL) { - *env << "IP multicast address " << inputAddressStr << ","; - } else { - *env << "unicast;"; - } - *env << " port " << inputPortNum << ")\n"; - announceURL(rtspServer, sms); - } - env->taskScheduler().doEventLoop(); // does not return return 0; // only to prevent compiler warning From e06143084ed1da9ed7044d506ac5047923675bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 18:54:21 +0200 Subject: [PATCH 06/31] step 1: reformat to reflect UG indentation --- src/rtsp/UltragridRTSPServer.cpp | 100 +++++++++++++++---------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index 1beaf49a78..d50407b10f 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -78,61 +78,59 @@ UsageEnvironment* env; Boolean reuseFirstSource = False; static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, - char const* streamName, char const* inputFileName); // forward + char const* streamName, char const* inputFileName); // forward int main(int argc, char** argv) { - // 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 - - // Create the RTSP server: - RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB); - if (rtspServer == NULL) { - *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; - exit(1); - } - - char const* descriptionString - = "Session streamed by \"testOnDemandRTSPServer\""; - - // Set up each of the possible streams that can be served by the - // RTSP server. Each such stream is implemented using a - // "ServerMediaSession" object, plus one or more - // "ServerMediaSubsession" objects for each audio/video substream. - - // A MPEG-4 video elementary stream: - { - char const* streamName = "mpeg4ESVideoTest"; - char const* inputFileName = "test.m4e"; - ServerMediaSession* sms - = ServerMediaSession::createNew(*env, streamName, streamName, - descriptionString); - sms->addSubsession(MPEG4VideoFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); - - announceStream(rtspServer, sms, streamName, inputFileName); - } - - env->taskScheduler().doEventLoop(); // does not return - - return 0; // only to prevent compiler warning + // 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 + + // Create the RTSP server: + RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB); + if (rtspServer == NULL) { + *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; + exit(1); + } + + char const* descriptionString = "Session streamed by \"testOnDemandRTSPServer\""; + + // Set up each of the possible streams that can be served by the + // RTSP server. Each such stream is implemented using a + // "ServerMediaSession" object, plus one or more + // "ServerMediaSubsession" objects for each audio/video substream. + + // A MPEG-4 video elementary stream: + { + char const* streamName = "mpeg4ESVideoTest"; + char const* inputFileName = "test.m4e"; + ServerMediaSession* sms = + ServerMediaSession::createNew(*env, streamName, streamName, descriptionString); + sms->addSubsession(MPEG4VideoFileServerMediaSubsession + ::createNew(*env, inputFileName, reuseFirstSource)); + rtspServer->addServerMediaSession(sms); + + announceStream(rtspServer, sms, streamName, inputFileName); + } + + env->taskScheduler().doEventLoop(); // does not return + + return 0; // only to prevent compiler warning } static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, - char const* streamName, char const* inputFileName) { - UsageEnvironment& env = rtspServer->envir(); + char const* streamName, char const* inputFileName) { + UsageEnvironment& env = rtspServer->envir(); - env << "\n\"" << streamName << "\" stream, from the file \"" - << inputFileName << "\"\n"; - announceURL(rtspServer, sms); + env << "\n\"" << streamName << "\" stream, from the file \"" + << inputFileName << "\"\n"; + announceURL(rtspServer, sms); } From 93bb022ada4a1635fcc5f45e150821e2cb9f3892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 18:58:15 +0200 Subject: [PATCH 07/31] step 2: add file to host rtsp server class --- src/rtsp/UltragridRTSPServer.hh | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/rtsp/UltragridRTSPServer.hh diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh new file mode 100644 index 0000000000..00298feb08 --- /dev/null +++ b/src/rtsp/UltragridRTSPServer.hh @@ -0,0 +1,46 @@ +/* + * 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 + * 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. + * + */ From 55a9f71240d6aa59e7adbf427b0d74bc3533dc80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 19:03:28 +0200 Subject: [PATCH 08/31] step 2: add rtsp server class, typedef to og name - basic structure for UltragridRTSPServer class - make copying not possible because server can't be copied - add typedef reference to name used in previous implementation --- src/rtsp/UltragridRTSPServer.hh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh index 00298feb08..61b615032a 100644 --- a/src/rtsp/UltragridRTSPServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -44,3 +44,25 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + +#ifndef ULTRAGRID_RTSP_SERVER_HH +#define ULTRAGRID_RTSP_SERVER_HH + +#include +#include + +class UltragridRTSPServer { +public: + UltragridRTSPServer(); + ~UltragridRTSPServer(); + + /** + * Copy constructor and copy assignment operator do not make sense in this context + */ + UltragridRTSPServer(const UltragridRTSPServer&) = delete; + UltragridRTSPServer& operator=(const UltragridRTSPServer&) = delete; +}; + +typedef UltragridRTSPServer BasicRTSPOnlyServer; // kept for legacy maintanance + +#endif // ULTRAGRID_RTSP_SERVER_HH From 56af87b4ab2a4cb82c024141898b58654a13021d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 19:15:25 +0200 Subject: [PATCH 09/31] step 2: move initialization logic to constructor move inicialization logic from main() to constructor of new class --- src/rtsp/UltragridRTSPServer.cpp | 10 ++-------- src/rtsp/UltragridRTSPServer.hh | 2 ++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index d50407b10f..ed9b9b12b7 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -65,22 +65,16 @@ along with this library; if not, write to the Free Software Foundation, Inc., **********/ // Copyright (c) 1996-2023, Live Networks, Inc. All rights reserved +#include "rtsp/UltragridRTSPServer.hh" #include "liveMedia.hh" #include "BasicUsageEnvironment.hh" #include "announceURL.hh" -UsageEnvironment* env; - -// To make the second and subsequent client for each stream reuse the same -// input stream as the first client (rather than playing the file from the -// start for each client), change the following "False" to "True": -Boolean reuseFirstSource = False; - static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, char const* streamName, char const* inputFileName); // forward -int main(int argc, char** argv) { +UltragridRTSPServer::UltragridRTSPServer() { // Begin by setting up our usage environment: TaskScheduler* scheduler = BasicTaskScheduler::createNew(); env = BasicUsageEnvironment::createNew(*scheduler); diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh index 61b615032a..004ef5dec6 100644 --- a/src/rtsp/UltragridRTSPServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -53,6 +53,8 @@ class UltragridRTSPServer { public: + UsageEnvironment* env; + UltragridRTSPServer(); ~UltragridRTSPServer(); From 91113c488647f11e01206366493ada6bc6cff776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 19:20:21 +0200 Subject: [PATCH 10/31] step 2: import announceURL function from Live555 - copied announceURL function from Live555 library at testProgs/announceURL.cpp - copied becase is functional and searchable for future modifications - function handles displaying url, that server listens on, to comandline --- src/rtsp/UltragridRTSPServer.cpp | 35 ++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index ed9b9b12b7..c66471cda5 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -47,6 +47,8 @@ /** * @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 @@ -66,13 +68,12 @@ along with this library; if not, write to the Free Software Foundation, Inc., // Copyright (c) 1996-2023, Live Networks, Inc. All rights reserved #include "rtsp/UltragridRTSPServer.hh" +#include // for "weHaveAnIPv*Address()" #include "liveMedia.hh" #include "BasicUsageEnvironment.hh" -#include "announceURL.hh" -static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, - char const* streamName, char const* inputFileName); // forward +void announceURL(RTSPServer* rtspServer, ServerMediaSession* sms); // forward UltragridRTSPServer::UltragridRTSPServer() { // Begin by setting up our usage environment: @@ -112,7 +113,7 @@ UltragridRTSPServer::UltragridRTSPServer() { ::createNew(*env, inputFileName, reuseFirstSource)); rtspServer->addServerMediaSession(sms); - announceStream(rtspServer, sms, streamName, inputFileName); + announceURL(rtspServer, sms); } env->taskScheduler().doEventLoop(); // does not return @@ -120,11 +121,23 @@ UltragridRTSPServer::UltragridRTSPServer() { return 0; // only to prevent compiler warning } -static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, - char const* streamName, char const* inputFileName) { - UsageEnvironment& env = rtspServer->envir(); - - env << "\n\"" << streamName << "\" stream, from the file \"" - << inputFileName << "\"\n"; - announceURL(rtspServer, sms); +// copied from Live555 library live555/testProgs/announceURL.cpp, published under LGPL3 licence +void 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"; } From b3435b425e2ed9302455dd8953090db7fcda19ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 19:25:35 +0200 Subject: [PATCH 11/31] step 2: add announceURL to class move announceURL function to class so funcitonality is more clear --- src/rtsp/UltragridRTSPServer.cpp | 4 +--- src/rtsp/UltragridRTSPServer.hh | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index c66471cda5..5c9145dc0f 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -73,8 +73,6 @@ along with this library; if not, write to the Free Software Foundation, Inc., #include "BasicUsageEnvironment.hh" -void announceURL(RTSPServer* rtspServer, ServerMediaSession* sms); // forward - UltragridRTSPServer::UltragridRTSPServer() { // Begin by setting up our usage environment: TaskScheduler* scheduler = BasicTaskScheduler::createNew(); @@ -122,7 +120,7 @@ UltragridRTSPServer::UltragridRTSPServer() { } // copied from Live555 library live555/testProgs/announceURL.cpp, published under LGPL3 licence -void announceURL(RTSPServer* rtspServer, ServerMediaSession* sms) { +void UltragridRTSPServer::announceURL(RTSPServer* rtspServer, ServerMediaSession* sms) { if (rtspServer == NULL || sms == NULL) return; // sanity check UsageEnvironment& env = rtspServer->envir(); diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh index 004ef5dec6..c6948af745 100644 --- a/src/rtsp/UltragridRTSPServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -63,6 +63,12 @@ public: */ 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); }; typedef UltragridRTSPServer BasicRTSPOnlyServer; // kept for legacy maintanance From cdc7d9f0c56cf47a183fb9b15c36476a7b3289a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 19:29:50 +0200 Subject: [PATCH 12/31] step 3: create base for media subsessions they will serve as container for various media transmitted by UG --- src/rtsp/UltragridRTSPSubsession.cpp | 48 ++++++++++++++++++++++++++++ src/rtsp/UltragridRTSPSubsession.hh | 46 ++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/rtsp/UltragridRTSPSubsession.cpp create mode 100644 src/rtsp/UltragridRTSPSubsession.hh diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp new file mode 100644 index 0000000000..5f20a3e7d7 --- /dev/null +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -0,0 +1,48 @@ +/* + * 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" diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh new file mode 100644 index 0000000000..80b5fa3aec --- /dev/null +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -0,0 +1,46 @@ +/* + * 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. + * + */ From 016f99585bc997d8c0d277d4610126b597127b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 19:39:25 +0200 Subject: [PATCH 13/31] step 3: repsesent UG rtp payload as subsession - add basic structure for UltragridRTSPSubsessionCommon class - add typedef reference to name used in previous implementation --- src/rtsp/UltragridRTSPSubsession.hh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh index 80b5fa3aec..93e897dd24 100644 --- a/src/rtsp/UltragridRTSPSubsession.hh +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -44,3 +44,29 @@ * 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 + +class UltragridRTSPSubsessionCommon { + UltragridRTSPSubsessionCommon(); +}; + +typedef UltragridRTSPSubsessionCommon BasicRTSPOnlySubsession; // kept for legacy maintanance + +#undef MAYBE_UNUSED_ATTRIBUTE + +#endif // BASIC_RTSP_SUBSESSION_HH From 558058de94f20ac61d69d0ac819ac75340785852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 20:05:31 +0200 Subject: [PATCH 14/31] step 3: inherit Live555 subsession functionality - add definitions for all needed functions - ServerMediaSubsession is chosen because it is common ancestor in Live555's subsessions --- src/rtsp/UltragridRTSPSubsession.cpp | 40 ++++++++++++++++++ src/rtsp/UltragridRTSPSubsession.hh | 61 +++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp index 5f20a3e7d7..41b58d3c63 100644 --- a/src/rtsp/UltragridRTSPSubsession.cpp +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -46,3 +46,43 @@ */ #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(int RTPPort) + : destPort(0), RTPPort(RTPPort) {} + +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; +} + +#undef MAYBE_UNUSED_ATTRIBUTE diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh index 93e897dd24..bd39d931e9 100644 --- a/src/rtsp/UltragridRTSPSubsession.hh +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -61,8 +61,65 @@ #define MAYBE_UNUSED_ATTRIBUTE // GCC complains if [[maybe_used]] is used there #endif -class UltragridRTSPSubsessionCommon { - UltragridRTSPSubsessionCommon(); +#include +#include + +class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { + UltragridRTSPSubsessionCommon(int RTPPort); + + /** + * @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 */) {} + + struct sockaddr_storage destAddress; + Port destPort; + + int RTPPort; + + const Boolean fReuseFirstSource = True; // tells Live555 that all clients use same source, eg. no pausing, seeking ... }; typedef UltragridRTSPSubsessionCommon BasicRTSPOnlySubsession; // kept for legacy maintanance From a4c52d739c64e4cfc9125814c6bcd82e00b47ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 21:30:04 +0200 Subject: [PATCH 15/31] step 3: provide a mechanism to direct media stream function redirectStream changes destination adress and port in UG module sender --- src/rtsp/UltragridRTSPSubsession.cpp | 24 ++++++++++++++++++++++-- src/rtsp/UltragridRTSPSubsession.hh | 10 +++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp index 41b58d3c63..a111664dda 100644 --- a/src/rtsp/UltragridRTSPSubsession.cpp +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -55,8 +55,8 @@ #define MAYBE_UNUSED_ATTRIBUTE // GCC complains if [[maybe_used]] is used there #endif -UltragridRTSPSubsessionCommon::UltragridRTSPSubsessionCommon(int RTPPort) - : destPort(0), RTPPort(RTPPort) {} +UltragridRTSPSubsessionCommon::UltragridRTSPSubsessionCommon(struct module *mod, int RTPPort, enum module_class *path_sender) + : destPort(0), mod(mod), RTPPort(RTPPort), path_sender(path_sender) {} void UltragridRTSPSubsessionCommon::getStreamParameters( MAYBE_UNUSED_ATTRIBUTE unsigned /* clientSessionId */, // in @@ -85,4 +85,24 @@ void UltragridRTSPSubsessionCommon::getStreamParameters( destPort = clientRTPPort; } +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 index bd39d931e9..a76d6623bb 100644 --- a/src/rtsp/UltragridRTSPSubsession.hh +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -63,9 +63,10 @@ #include #include +#include "module.h" class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { - UltragridRTSPSubsessionCommon(int RTPPort); + UltragridRTSPSubsessionCommon(struct module *mod, int RTPPort, enum module_class *path_sender); /** * @note called by Live555 when handling SETUP method @@ -114,11 +115,18 @@ class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { 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); + 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 ... }; From 11b3012fb3f1d798ade7bb500324fe5a098d81fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 8 Oct 2023 21:41:37 +0200 Subject: [PATCH 16/31] step 3: implement RTSP playback control - starts stream by changing destination adress and port to the ones got in function getStreamParameters - deletes stream by changing destination address and port to localhost --- src/rtsp/UltragridRTSPSubsession.cpp | 33 ++++++++++++++++++++++++++-- src/rtsp/UltragridRTSPSubsession.hh | 3 ++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp index a111664dda..56bae36756 100644 --- a/src/rtsp/UltragridRTSPSubsession.cpp +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -55,8 +55,11 @@ #define MAYBE_UNUSED_ATTRIBUTE // GCC complains if [[maybe_used]] is used there #endif -UltragridRTSPSubsessionCommon::UltragridRTSPSubsessionCommon(struct module *mod, int RTPPort, enum module_class *path_sender) - : destPort(0), mod(mod), RTPPort(RTPPort), path_sender(path_sender) {} +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(); +} void UltragridRTSPSubsessionCommon::getStreamParameters( MAYBE_UNUSED_ATTRIBUTE unsigned /* clientSessionId */, // in @@ -85,6 +88,32 @@ void UltragridRTSPSubsessionCommon::getStreamParameters( 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)); diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh index a76d6623bb..260834c8bf 100644 --- a/src/rtsp/UltragridRTSPSubsession.hh +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -66,7 +66,7 @@ #include "module.h" class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { - UltragridRTSPSubsessionCommon(struct module *mod, int RTPPort, enum module_class *path_sender); + UltragridRTSPSubsessionCommon(UsageEnvironment& env, struct module *mod, int RTPPort, enum module_class *path_sender); /** * @note called by Live555 when handling SETUP method @@ -120,6 +120,7 @@ class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { */ void redirectStream(const char* destinationAddress, int destinationPort); + UsageEnvironment& env; struct sockaddr_storage destAddress; Port destPort; From 22db40cf3b0f7d749e79b47932450be57a46a734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sat, 14 Oct 2023 21:25:03 +0200 Subject: [PATCH 17/31] step 4: instantiate subsession for audio and video - inherits from UltragridRTSPSubsessionCommon because implementation of needed functions (by ServerMediaSubsession) is the same - exept for SDP Lines which are added later - Factory method (createNew) is used because Live555 library needs pointer to structure and all subsessions in Live555 library are created this way --- src/rtsp/UltragridRTSPSubsession.cpp | 14 ++++++++++++++ src/rtsp/UltragridRTSPSubsession.hh | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp index 56bae36756..4f2ad5cb21 100644 --- a/src/rtsp/UltragridRTSPSubsession.cpp +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -61,6 +61,20 @@ UltragridRTSPSubsessionCommon::UltragridRTSPSubsessionCommon(UsageEnvironment& e 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, nullptr) {} + +UltragridRTSPAudioSubsession* UltragridRTSPAudioSubsession::createNew(UsageEnvironment& env, struct module *mod, int RTPPort) { + return new UltragridRTSPAudioSubsession(env, mod, RTPPort); +} + +UltragridRTSPAudioSubsession::UltragridRTSPAudioSubsession(UsageEnvironment& env, struct module *mod, int RTPPort) + : UltragridRTSPSubsessionCommon(env, mod, RTPPort, nullptr) {} + void UltragridRTSPSubsessionCommon::getStreamParameters( MAYBE_UNUSED_ATTRIBUTE unsigned /* clientSessionId */, // in MAYBE_UNUSED_ATTRIBUTE struct sockaddr_storage const& clientAddress, // in diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh index 260834c8bf..43035a2476 100644 --- a/src/rtsp/UltragridRTSPSubsession.hh +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -66,6 +66,7 @@ #include "module.h" class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { +protected: UltragridRTSPSubsessionCommon(UsageEnvironment& env, struct module *mod, int RTPPort, enum module_class *path_sender); /** @@ -131,6 +132,18 @@ class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { 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); +}; + +class UltragridRTSPAudioSubsession: public UltragridRTSPSubsessionCommon { +public: + static UltragridRTSPAudioSubsession* createNew(UsageEnvironment& env, struct module *mod, int RTPPort); + UltragridRTSPAudioSubsession(UsageEnvironment& env, struct module *mod, int RTPPort); +}; + typedef UltragridRTSPSubsessionCommon BasicRTSPOnlySubsession; // kept for legacy maintanance #undef MAYBE_UNUSED_ATTRIBUTE From fd129c8540f17c753fe72d0d51c72f59bdac9145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sat, 14 Oct 2023 21:42:50 +0200 Subject: [PATCH 18/31] step 4: specify modules for directing media stream - Tell UG what modules shoud be notified when changing direction of media stream - MODULE_CLASS_SENDER - controls video stream - MODULE_CLASS_AUDIO - controls audio stream - MODULE_CLASS_NONE - only used as stop (like \0 in string) --- src/rtsp/UltragridRTSPSubsession.cpp | 4 ++-- src/rtsp/UltragridRTSPSubsession.hh | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp index 4f2ad5cb21..976b96788c 100644 --- a/src/rtsp/UltragridRTSPSubsession.cpp +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -66,14 +66,14 @@ UltragridRTSPVideoSubsession* UltragridRTSPVideoSubsession::createNew(UsageEnvir } UltragridRTSPVideoSubsession::UltragridRTSPVideoSubsession(UsageEnvironment& env, struct module *mod, int RTPPort) - : UltragridRTSPSubsessionCommon(env, mod, RTPPort, nullptr) {} + : UltragridRTSPSubsessionCommon(env, mod, RTPPort, path_sender) {} UltragridRTSPAudioSubsession* UltragridRTSPAudioSubsession::createNew(UsageEnvironment& env, struct module *mod, int RTPPort) { return new UltragridRTSPAudioSubsession(env, mod, RTPPort); } UltragridRTSPAudioSubsession::UltragridRTSPAudioSubsession(UsageEnvironment& env, struct module *mod, int RTPPort) - : UltragridRTSPSubsessionCommon(env, mod, RTPPort, nullptr) {} + : UltragridRTSPSubsessionCommon(env, mod, RTPPort, path_sender) {} void UltragridRTSPSubsessionCommon::getStreamParameters( MAYBE_UNUSED_ATTRIBUTE unsigned /* clientSessionId */, // in diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh index 43035a2476..75d35e5244 100644 --- a/src/rtsp/UltragridRTSPSubsession.hh +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -136,12 +136,18 @@ class UltragridRTSPVideoSubsession: public UltragridRTSPSubsessionCommon { public: static UltragridRTSPVideoSubsession* createNew(UsageEnvironment& env, struct module *mod, int RTPPort); UltragridRTSPVideoSubsession(UsageEnvironment& env, struct module *mod, int RTPPort); + +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); UltragridRTSPAudioSubsession(UsageEnvironment& env, struct module *mod, int RTPPort); + +private: + 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 From a0e319bf2f7498fcd2c8d913e31a6eea6dba7f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sat, 14 Oct 2023 21:52:40 +0200 Subject: [PATCH 19/31] step 4: generate SDP description of media stream Generate description of provided media according to SDP protocol defined in RFC 8866 with modifications for RTSP protocol defined in RFC 2326 --- src/rtsp/UltragridRTSPSubsession.cpp | 58 ++++++++++++++++++++++++++-- src/rtsp/UltragridRTSPSubsession.hh | 29 +++++++++++++- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/rtsp/UltragridRTSPSubsession.cpp b/src/rtsp/UltragridRTSPSubsession.cpp index 976b96788c..6536ccd8c2 100644 --- a/src/rtsp/UltragridRTSPSubsession.cpp +++ b/src/rtsp/UltragridRTSPSubsession.cpp @@ -68,12 +68,62 @@ UltragridRTSPVideoSubsession* UltragridRTSPVideoSubsession::createNew(UsageEnvir 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) { - return new UltragridRTSPAudioSubsession(env, mod, RTPPort); +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) - : UltragridRTSPSubsessionCommon(env, mod, RTPPort, path_sender) {} +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 diff --git a/src/rtsp/UltragridRTSPSubsession.hh b/src/rtsp/UltragridRTSPSubsession.hh index 75d35e5244..fe4f7c4095 100644 --- a/src/rtsp/UltragridRTSPSubsession.hh +++ b/src/rtsp/UltragridRTSPSubsession.hh @@ -63,6 +63,7 @@ #include #include +#include "audio/types.h" #include "module.h" class UltragridRTSPSubsessionCommon: public ServerMediaSubsession { @@ -122,6 +123,7 @@ protected: void redirectStream(const char* destinationAddress, int destinationPort); UsageEnvironment& env; + std::string SDPLines; struct sockaddr_storage destAddress; Port destPort; @@ -137,16 +139,39 @@ 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); - UltragridRTSPAudioSubsession(UsageEnvironment& env, struct module *mod, int RTPPort); + 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 }; From d044850913bc52253e23be7a29eff9b45e7134b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sat, 14 Oct 2023 22:31:10 +0200 Subject: [PATCH 20/31] step 5: add way to specify port for rtsp server - if user don't specify port number default 8554 will be used - Live555 does not have mechanism to tell if port is already in use so user must specify available port --- src/rtsp/UltragridRTSPServer.cpp | 13 ++++++++----- src/rtsp/UltragridRTSPServer.hh | 4 +++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index 5c9145dc0f..e8c10edc28 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -73,7 +73,7 @@ along with this library; if not, write to the Free Software Foundation, Inc., #include "BasicUsageEnvironment.hh" -UltragridRTSPServer::UltragridRTSPServer() { +UltragridRTSPServer::UltragridRTSPServer(unsigned int rtsp_port) { // Begin by setting up our usage environment: TaskScheduler* scheduler = BasicTaskScheduler::createNew(); env = BasicUsageEnvironment::createNew(*scheduler); @@ -87,11 +87,14 @@ UltragridRTSPServer::UltragridRTSPServer() { // access to the server. #endif - // Create the RTSP server: - RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB); + 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 << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; - exit(1); + *env << "[RTSP Server] Error: Failed to create RTSP server: " << env->getResultMsg() << "\n"; + throw std::system_error(); } char const* descriptionString = "Session streamed by \"testOnDemandRTSPServer\""; diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh index c6948af745..e3a897350b 100644 --- a/src/rtsp/UltragridRTSPServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -55,7 +55,7 @@ class UltragridRTSPServer { public: UsageEnvironment* env; - UltragridRTSPServer(); + UltragridRTSPServer(unsigned int rtsp_port); ~UltragridRTSPServer(); /** @@ -69,6 +69,8 @@ private: * @note Copied as is from live555/testProgs/announceURL.hh. */ static void announceURL(RTSPServer* rtspServer, ServerMediaSession* sms); + + RTSPServer* rtspServer; }; typedef UltragridRTSPServer BasicRTSPOnlyServer; // kept for legacy maintanance From 1daa3c4265cc5e2de006375f083b49bf7ae9dd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 15:09:12 +0200 Subject: [PATCH 21/31] step 5: add supported media types, rename refs in previous version of rtsp_utils.h file the struct was named differently so all references have to be renamed --- src/main.cpp | 12 ++++---- src/rtsp/rtsp_utils.h | 59 +++++++++++++++++++++++++++++++++++++ src/video_capture/rtsp.c | 4 +-- src/video_rxtx/h264_rtp.cpp | 2 +- 4 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 src/rtsp/rtsp_utils.h diff --git a/src/main.cpp b/src/main.cpp index aee9c0ba91..852a0d8232 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1480,16 +1480,16 @@ int main(int argc, char *argv[]) params["a_tx_port"].i = opt.audio.send_port; 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/rtsp_utils.h b/src/rtsp/rtsp_utils.h new file mode 100644 index 0000000000..5ee8037b3d --- /dev/null +++ b/src/rtsp/rtsp_utils.h @@ -0,0 +1,59 @@ +/* + * 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_MEDIA_TYPES +} rtsp_media_type_t; + +#endif // RTSP_UTILS_H 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..3d8703e7f0 100644 --- a/src/video_rxtx/h264_rtp.cpp +++ b/src/video_rxtx/h264_rtp.cpp @@ -73,7 +73,7 @@ h264_rtp_video_rxtx::h264_rtp_video_rxtx(std::map const &p { m_rtsp_server = init_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); From ec1b85a2e952decf36b8f5230601d5a000191160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 14:35:55 +0200 Subject: [PATCH 22/31] step 5: instantiate subsessions for rtsp server replace MPEG-4 example with new subsessions made for UG --- src/rtsp/UltragridRTSPServer.cpp | 39 ++++++++++++++++---------------- src/rtsp/UltragridRTSPServer.hh | 12 +++++++++- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index e8c10edc28..da0b89282c 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -68,12 +68,14 @@ along with this library; if not, write to the Free Software Foundation, Inc., // Copyright (c) 1996-2023, Live Networks, Inc. All rights reserved #include "rtsp/UltragridRTSPServer.hh" +#include "rtsp/UltragridRTSPSubsession.hh" #include // for "weHaveAnIPv*Address()" -#include "liveMedia.hh" -#include "BasicUsageEnvironment.hh" +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 audio_bps, int rtp_video_port, int rtp_audio_port) { + if(mod == NULL) + throw std::system_error(); -UltragridRTSPServer::UltragridRTSPServer(unsigned int rtsp_port) { // Begin by setting up our usage environment: TaskScheduler* scheduler = BasicTaskScheduler::createNew(); env = BasicUsageEnvironment::createNew(*scheduler); @@ -97,25 +99,24 @@ UltragridRTSPServer::UltragridRTSPServer(unsigned int rtsp_port) { throw std::system_error(); } - char const* descriptionString = "Session streamed by \"testOnDemandRTSPServer\""; - - // Set up each of the possible streams that can be served by the - // RTSP server. Each such stream is implemented using a - // "ServerMediaSession" object, plus one or more - // "ServerMediaSubsession" objects for each audio/video substream. + ServerMediaSession* sms = ServerMediaSession::createNew(*env, "ultragrid", "UltraGrid RTSP server enabling standard transport", "UltraGrid RTSP server"); - // A MPEG-4 video elementary stream: - { - char const* streamName = "mpeg4ESVideoTest"; - char const* inputFileName = "test.m4e"; - ServerMediaSession* sms = - ServerMediaSession::createNew(*env, streamName, streamName, descriptionString); - sms->addSubsession(MPEG4VideoFileServerMediaSubsession - ::createNew(*env, inputFileName, reuseFirstSource)); - rtspServer->addServerMediaSession(sms); + 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)); - announceURL(rtspServer, sms); + 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); env->taskScheduler().doEventLoop(); // does not return diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh index e3a897350b..c5fc247393 100644 --- a/src/rtsp/UltragridRTSPServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -50,12 +50,22 @@ #include #include +#include "rtsp/rtsp_utils.h" +#include "audio/types.h" +#include "module.h" +/** + * 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: UsageEnvironment* env; - UltragridRTSPServer(unsigned int rtsp_port); + 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 audio_bps, int rtp_video_port, int rtp_audio_port); ~UltragridRTSPServer(); /** From 8489d1238fc0a476d9b7f61d563758066fcc6f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 15:03:51 +0200 Subject: [PATCH 23/31] step 5: extract starting server from constructor - serverStopFlag if set to 0 server is running when set to 1 it stops - serverRunner built so it can be launched from pthread_create - destructor cleans memory --- src/rtsp/UltragridRTSPServer.cpp | 14 ++++++++++++-- src/rtsp/UltragridRTSPServer.hh | 8 ++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index da0b89282c..aa905f1ed6 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -117,10 +117,20 @@ UltragridRTSPServer::UltragridRTSPServer(unsigned int rtsp_port, struct module* rtspServer->addServerMediaSession(sms); announceURL(rtspServer, sms); +} - env->taskScheduler().doEventLoop(); // does not return +UltragridRTSPServer::~UltragridRTSPServer() { + if (rtspServer != NULL) { + Medium::close(rtspServer); + } + if (env != NULL) { + delete &env->taskScheduler(); + env->reclaim(); + } +} - return 0; // only to prevent compiler warning +void UltragridRTSPServer::serverRunner(char* serverStopFlag) { + env->taskScheduler().doEventLoop(serverStopFlag); } // copied from Live555 library live555/testProgs/announceURL.cpp, published under LGPL3 licence diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh index c5fc247393..5eaa974117 100644 --- a/src/rtsp/UltragridRTSPServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -68,6 +68,14 @@ public: int audio_sample_rate, int audio_channels, int audio_bps, int rtp_video_port, int rtp_audio_port); ~UltragridRTSPServer(); + /** + * 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); + /** * Copy constructor and copy assignment operator do not make sense in this context */ From 5f5662d83585512babc2554599d9e6e626735ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 15:18:16 +0200 Subject: [PATCH 24/31] step 6: add files to host rtsp server management they will be used by UG to interface with rtsp server --- src/rtsp/ultragrid_rtsp.cpp | 46 +++++++++++++++++++++++++++++++++++++ src/rtsp/ultragrid_rtsp.hh | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/rtsp/ultragrid_rtsp.cpp create mode 100644 src/rtsp/ultragrid_rtsp.hh diff --git a/src/rtsp/ultragrid_rtsp.cpp b/src/rtsp/ultragrid_rtsp.cpp new file mode 100644 index 0000000000..bdc8bf77d1 --- /dev/null +++ b/src/rtsp/ultragrid_rtsp.cpp @@ -0,0 +1,46 @@ +/* + * 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 + * 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. + * + */ diff --git a/src/rtsp/ultragrid_rtsp.hh b/src/rtsp/ultragrid_rtsp.hh new file mode 100644 index 0000000000..a0d66e767a --- /dev/null +++ b/src/rtsp/ultragrid_rtsp.hh @@ -0,0 +1,46 @@ +/* + * 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 + * 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. + * + */ From 0d146ffcf2698009018d965ac29d3a3a5f4a9004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 15:31:35 +0200 Subject: [PATCH 25/31] step 6: class to manage rtsp server - basic structure of ultragrid_rtsp class - it provides control of rtsp server --- src/rtsp/ultragrid_rtsp.cpp | 8 ++++++++ src/rtsp/ultragrid_rtsp.hh | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/rtsp/ultragrid_rtsp.cpp b/src/rtsp/ultragrid_rtsp.cpp index bdc8bf77d1..a8b127eb30 100644 --- a/src/rtsp/ultragrid_rtsp.cpp +++ b/src/rtsp/ultragrid_rtsp.cpp @@ -44,3 +44,11 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + +#include "rtsp/ultragrid_rtsp.hh" +#include "rtsp/UltragridRTSPServer.hh" + +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 audio_bps, int rtp_video_port, int rtp_audio_port) { + rtsp_server = std::make_unique(rtsp_port, mod, media_type, audio_codec, audio_sample_rate, audio_channels, audio_bps, rtp_video_port, rtp_audio_port); +} diff --git a/src/rtsp/ultragrid_rtsp.hh b/src/rtsp/ultragrid_rtsp.hh index a0d66e767a..897e6a0701 100644 --- a/src/rtsp/ultragrid_rtsp.hh +++ b/src/rtsp/ultragrid_rtsp.hh @@ -44,3 +44,35 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + +#ifndef ULTRAGRID_RTSP_HH +#define ULTRAGRID_RTSP_HH + +#include "rtsp/rtsp_utils.h" +#include "audio/types.h" +#include "module.h" + +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 audio_bps, int rtp_video_port, int rtp_audio_port); + ~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; + +private: + + std::unique_ptr rtsp_server; // pointer to avoid name clashes with live555 +}; + +#endif // ULTRAGRID_RTSP_HH From 244370c69e8fe06f2e1a64a94cea59ad5157d6cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 15:50:49 +0200 Subject: [PATCH 26/31] step 6: start and stop server thread - new thread is created for rtsp server because control flow needs to be given to Live555 - server stops by setting server_stop_flag to 1 - char is used because it is needed by Live555 library - because rtsp server does not need to know about threads two 'runner' functions are used to separate server and threads --- src/rtsp/ultragrid_rtsp.cpp | 33 ++++++++++++++++++++++++++++++++- src/rtsp/ultragrid_rtsp.hh | 19 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/rtsp/ultragrid_rtsp.cpp b/src/rtsp/ultragrid_rtsp.cpp index a8b127eb30..7dec8f9b2e 100644 --- a/src/rtsp/ultragrid_rtsp.cpp +++ b/src/rtsp/ultragrid_rtsp.cpp @@ -49,6 +49,37 @@ #include "rtsp/UltragridRTSPServer.hh" 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 audio_bps, int rtp_video_port, int rtp_audio_port) { + int audio_sample_rate, int audio_channels, int audio_bps, 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, audio_bps, rtp_video_port, rtp_audio_port); } + +ultragrid_rtsp::~ultragrid_rtsp() { + stop_server(); +} + +int ultragrid_rtsp::start_server() { + if (thread_running) + return 1; + server_stop_flag = 0; + + int ret; + ret = pthread_create(&server_thread, NULL, ultragrid_rtsp::server_runner, this); + thread_running = (ret == 0) ? true : false; + return ret; +} + +void ultragrid_rtsp::stop_server() { + server_stop_flag = 1; + + 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/ultragrid_rtsp.hh b/src/rtsp/ultragrid_rtsp.hh index 897e6a0701..f361d5746e 100644 --- a/src/rtsp/ultragrid_rtsp.hh +++ b/src/rtsp/ultragrid_rtsp.hh @@ -48,6 +48,7 @@ #ifndef ULTRAGRID_RTSP_HH #define ULTRAGRID_RTSP_HH +#include #include "rtsp/rtsp_utils.h" #include "audio/types.h" #include "module.h" @@ -62,6 +63,9 @@ public: */ 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 audio_bps, int rtp_video_port, int rtp_audio_port); + /** + * Stops server and frees any allocated memory + */ ~ultragrid_rtsp(); /** @@ -70,8 +74,23 @@ public: 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 }; From 23665b1349fee41a867350ff415e497a2ebb1fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 15:59:10 +0200 Subject: [PATCH 27/31] step 7: redirect configure to new implementation --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0820bd4adc..5e66bdcb02 100644 --- a/configure.ac +++ b/configure.ac @@ -1426,7 +1426,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 From b0743d3a798da1c9fdea0d790ad91b72a374e058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sat, 16 Dec 2023 17:11:46 +0100 Subject: [PATCH 28/31] step 7: remove Live555 library version check new implementation is built on version 2023.11.30 of Live555 --- configure.ac | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 5e66bdcb02..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 From e7e1c5d2b248cd5150c08302cd9c74084533cd61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 16:22:47 +0200 Subject: [PATCH 29/31] step 7: modify h264 rxtx to reflect changes in rtsp server --- src/video_rxtx/h264_rtp.cpp | 57 ++++++++++++++++--------------------- src/video_rxtx/h264_rtp.hpp | 6 ++-- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/video_rxtx/h264_rtp.cpp b/src/video_rxtx/h264_rtp.cpp index 3d8703e7f0..61abef7ec4 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("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("audio_bps").i, 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_ From c536024107bb9d209e0e29ac4da307c8ebe973f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sat, 16 Dec 2023 15:10:20 +0100 Subject: [PATCH 30/31] step 7: override number of channels for OPUS - OPUS does not support mono - RFC 7587 specifies that in SDP number of channels must be 2 --- src/main.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 852a0d8232..e091889b47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1474,11 +1474,17 @@ 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) { 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 From f7c559d195cc544bd667a2aa6121b27d030d2c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kov=C3=A1=C4=8D?= Date: Sun, 15 Oct 2023 16:26:50 +0200 Subject: [PATCH 31/31] step 7: remove unused parameter - in previous implementation parameter audio_bps was used in initialization of rtsp server but was not used internally - it is kept in the process of creating new implementaion (git commits) for reference with previous implementaion --- src/rtsp/UltragridRTSPServer.cpp | 2 +- src/rtsp/UltragridRTSPServer.hh | 2 +- src/rtsp/ultragrid_rtsp.cpp | 4 ++-- src/rtsp/ultragrid_rtsp.hh | 2 +- src/video_rxtx/h264_rtp.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rtsp/UltragridRTSPServer.cpp b/src/rtsp/UltragridRTSPServer.cpp index aa905f1ed6..c86dcc37be 100644 --- a/src/rtsp/UltragridRTSPServer.cpp +++ b/src/rtsp/UltragridRTSPServer.cpp @@ -72,7 +72,7 @@ along with this library; if not, write to the Free Software Foundation, Inc., #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 audio_bps, int rtp_video_port, int rtp_audio_port) { + int audio_sample_rate, int audio_channels, int rtp_video_port, int rtp_audio_port) { if(mod == NULL) throw std::system_error(); diff --git a/src/rtsp/UltragridRTSPServer.hh b/src/rtsp/UltragridRTSPServer.hh index 5eaa974117..8b26872cbb 100644 --- a/src/rtsp/UltragridRTSPServer.hh +++ b/src/rtsp/UltragridRTSPServer.hh @@ -65,7 +65,7 @@ public: UsageEnvironment* env; 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 audio_bps, int rtp_video_port, int rtp_audio_port); + int audio_sample_rate, int audio_channels, int rtp_video_port, int rtp_audio_port); ~UltragridRTSPServer(); /** diff --git a/src/rtsp/ultragrid_rtsp.cpp b/src/rtsp/ultragrid_rtsp.cpp index 7dec8f9b2e..90a0878d40 100644 --- a/src/rtsp/ultragrid_rtsp.cpp +++ b/src/rtsp/ultragrid_rtsp.cpp @@ -49,9 +49,9 @@ #include "rtsp/UltragridRTSPServer.hh" 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 audio_bps, int rtp_video_port, int rtp_audio_port) + 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, audio_bps, rtp_video_port, rtp_audio_port); + 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() { diff --git a/src/rtsp/ultragrid_rtsp.hh b/src/rtsp/ultragrid_rtsp.hh index f361d5746e..b99d4cd1d3 100644 --- a/src/rtsp/ultragrid_rtsp.hh +++ b/src/rtsp/ultragrid_rtsp.hh @@ -62,7 +62,7 @@ public: * 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 audio_bps, int rtp_video_port, int rtp_audio_port); + int audio_sample_rate, int audio_channels, int rtp_video_port, int rtp_audio_port); /** * Stops server and frees any allocated memory */ diff --git a/src/video_rxtx/h264_rtp.cpp b/src/video_rxtx/h264_rtp.cpp index 61abef7ec4..c83f2a07d7 100644 --- a/src/video_rxtx/h264_rtp.cpp +++ b/src/video_rxtx/h264_rtp.cpp @@ -76,7 +76,7 @@ h264_rtp_video_rxtx::h264_rtp_video_rxtx(std::map const &p 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) + params.at("rx_port").i, params.at("a_rx_port").i) #endif // HAVE_RTSP_SERVER { #ifdef HAVE_RTSP_SERVER