Groupsock* GroupsockLookupTable::AddNew(UsageEnvironment& env, netAddressBits groupAddress, netAddressBits sourceFilterAddress, Port port, u_int8_t ttl) { Groupsock* groupsock; do { struct in_addr groupAddr; groupAddr.s_addr = groupAddress; if (sourceFilterAddress == netAddressBits(~0)) { // regular, ISM groupsock groupsock = new Groupsock(env, groupAddr, port, ttl); } else { // SSM groupsock struct in_addr sourceFilterAddr; sourceFilterAddr.s_addr = sourceFilterAddress; groupsock = new Groupsock(env, groupAddr, sourceFilterAddr, port); } if (groupsock == NULL || groupsock->socketNum() < 0) break; if (!setGroupsockBySocket(env, groupsock->socketNum(), groupsock)) break; fTable.Add(groupAddress, sourceFilterAddress, port, (void*)groupsock); } while (0); return groupsock; }
void StreamState::endPlaying(Destinations* dests, char *videotype, char *audiotype) { Debug(ckite_log_message, "StreamState::endPlaying\n"); if (dests->isTCP) { if (fRTPSink != NULL) { if (strcmp(videotype, "store") == 0 || strcmp(audiotype, "store") == 0) { }else{ fRTPSink->removeStreamSocket(dests->tcpSocketNum, dests->rtpChannelId); } } if (fRTCPInstance != NULL) { if (strcmp(videotype, "store") == 0 || strcmp(audiotype, "store") == 0) { }else{ fRTCPInstance->removeStreamSocket(dests->tcpSocketNum, dests->rtcpChannelId); } fRTCPInstance->setSpecificRRHandler(dests->tcpSocketNum, dests->rtcpChannelId, NULL, NULL); } } else { // Tell the RTP and RTCP 'groupsocks' to stop using these destinations: if (fRTPgs != NULL) fRTPgs->removeDestination(dests->addr, dests->rtpPort); if (fRTCPgs != NULL) fRTCPgs->removeDestination(dests->addr, dests->rtcpPort); if (fRTCPInstance != NULL) { fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr, dests->rtcpPort, NULL, NULL); } } }
static Boolean unsetGroupsockBySocket(Groupsock const* groupsock) { do { if (groupsock == NULL) break; int sock = groupsock->socketNum(); // Make sure "sock" is in bounds: if (sock < 0) break; HashTable* sockets = getSocketTable(groupsock->env()); if (sockets == NULL) break; Groupsock* gs = (Groupsock*)sockets->Lookup((char*)(long)sock); if (gs == NULL || gs != groupsock) break; sockets->Remove((char*)(long)sock); if (sockets->IsEmpty()) { // We can also delete the table (to reclaim space): delete sockets; (gs->env()).groupsockPriv = NULL; } return True; } while (0); return False; }
void PassiveServerMediaSubsession ::getStreamParameters(unsigned /*clientSessionId*/, netAddressBits /*clientAddress*/, Port const& /*clientRTPPort*/, Port const& /*clientRTCPPort*/, int /*tcpSocketNum*/, unsigned char /*rtpChannelId*/, unsigned char /*rtcpChannelId*/, netAddressBits& destinationAddress, u_int8_t& destinationTTL, Boolean& isMulticast, Port& serverRTPPort, Port& serverRTCPPort, void*& streamToken) { isMulticast = True; Groupsock& gs = fRTPSink.groupsockBeingUsed(); if (destinationTTL == 255) destinationTTL = gs.ttl(); if (destinationAddress == 0) { // normal case destinationAddress = gs.groupAddress().s_addr; } else { // use the client-specified destination address instead: struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress; gs.changeDestinationParameters(destinationAddr, 0, destinationTTL); if (fRTCPInstance != NULL) { Groupsock* rtcpGS = fRTCPInstance->RTCPgs(); rtcpGS->changeDestinationParameters(destinationAddr, 0, destinationTTL); } } serverRTPPort = gs.port(); if (fRTCPInstance != NULL) { Groupsock* rtcpGS = fRTCPInstance->RTCPgs(); serverRTCPPort = rtcpGS->port(); } streamToken = NULL; // not used }
void StreamState ::startPlaying(Destinations* dests, TaskFunc* rtcpRRHandler, void* rtcpRRHandlerClientData) { if (dests == NULL) return; //skip play action if it's already being played if (!fAreCurrentlyPlaying && fMediaSource != NULL) { if (fRTPSink != NULL) { fRTPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); fAreCurrentlyPlaying = True; } else if (fUDPSink != NULL) { fUDPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); fAreCurrentlyPlaying = True; } createWorkingThread(); } if (fRTCPInstance == NULL && fRTPSink != NULL) { // Create (and start) a 'RTCP instance' for this RTP sink: fRTCPInstance // = RTCPInstance::createNew(fRTPSink->envir(), fRTCPgs, = RTCPInstance::createNew(fRtcpEnv, fRTCPgs, fTotalBW, (unsigned char*)fMaster.fCNAME, fRTPSink, NULL /* we're a server */); // Note: This starts RTCP running automatically } if (dests->isTCP) { // Change RTP and RTCP to use the TCP socket instead of UDP: if (fRTPSink != NULL) { fRTPSink->addStreamSocket(dests->tcpSocketNum, dests->rtpChannelId); } if (fRTCPInstance != NULL) { fRTCPInstance->addStreamSocket(dests->tcpSocketNum, dests->rtcpChannelId); fRTCPInstance->setSpecificRRHandler(dests->tcpSocketNum, dests->rtcpChannelId, rtcpRRHandler, rtcpRRHandlerClientData); } } else { // Tell the RTP and RTCP 'groupsocks' about this destination // (in case they don't already have it): // printf("addDestination %s\n", inet_ntoa(dests->addr)); //jay if (fRTPgs != NULL) fRTPgs->addDestination(dests->addr, dests->rtpPort); if (fRTCPgs != NULL) fRTCPgs->addDestination(dests->addr, dests->rtcpPort); if (fRTCPInstance != NULL) { if (!IsMulticastAddress(dests->addr.s_addr)) { fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr, dests->rtcpPort, rtcpRRHandler, rtcpRRHandlerClientData); } } } }
static void NATHolePunch(RTPSource *rtpsrc, MediaSubsession *subsession) { Groupsock *gs = NULL; int s; struct sockaddr_in sin; unsigned char buf[1] = { 0x00 }; #ifdef WIN32 int sinlen = sizeof(sin); #else socklen_t sinlen = sizeof(sin); #endif if(rtspconf->sin.sin_addr.s_addr == 0 || rtspconf->sin.sin_addr.s_addr == INADDR_NONE) { rtsperror("NAT hole punching: no server address available.\n"); return; } if(rtpsrc == NULL) { rtsperror("NAT hole punching: no RTPSource available.\n"); return; } if(subsession == NULL) { rtsperror("NAT hole punching: no subsession available.\n"); return; } gs = rtpsrc->RTPgs(); if(gs == NULL) { rtsperror("NAT hole punching: no Groupsock available.\n"); return; } // s = gs->socketNum(); if(getsockname(s, (struct sockaddr*) &sin, &sinlen) < 0) { rtsperror("NAT hole punching: getsockname - %s.\n", strerror(errno)); return; } rtsperror("NAT hole punching: fd=%d, local-port=%d/%d server-port=%d\n", s, ntohs(sin.sin_port), subsession->clientPortNum(), subsession->serverPortNum); // bzero(&sin, sizeof(sin)); sin.sin_addr = rtspconf->sin.sin_addr; sin.sin_port = htons(subsession->serverPortNum); // send 5 packets // XXX: use const char * for buf pointer to work with Windows sendto(s, (const char *) buf, 1, 0, (struct sockaddr*) &sin, sizeof(sin)); usleep(5000); sendto(s, (const char *) buf, 1, 0, (struct sockaddr*) &sin, sizeof(sin)); usleep(5000); sendto(s, (const char *) buf, 1, 0, (struct sockaddr*) &sin, sizeof(sin)); usleep(5000); sendto(s, (const char *) buf, 1, 0, (struct sockaddr*) &sin, sizeof(sin)); usleep(5000); sendto(s, (const char *) buf, 1, 0, (struct sockaddr*) &sin, sizeof(sin)); usleep(5000); // return; }
void StreamState ::startPlaying(Destinations* dests, TaskFunc* rtcpRRHandler, void* rtcpRRHandlerClientData, ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, void* serverRequestAlternativeByteHandlerClientData) { if (dests == NULL) return; if (fRTCPInstance == NULL && fRTPSink != NULL) { // Create (and start) a 'RTCP instance' for this RTP sink: fRTCPInstance = RTCPInstance::createNew(fRTPSink->envir(), fRTCPgs, fTotalBW, (unsigned char*)fMaster.fCNAME, fRTPSink, NULL /* we're a server */); // Note: This starts RTCP running automatically } if (dests->isTCP) { // Change RTP and RTCP to use the TCP socket instead of UDP: if (fRTPSink != NULL) { fRTPSink->addStreamSocket(dests->tcpSocketNum, dests->rtpChannelId); fRTPSink->setServerRequestAlternativeByteHandler(dests->tcpSocketNum, serverRequestAlternativeByteHandler, serverRequestAlternativeByteHandlerClientData); } if (fRTCPInstance != NULL) { fRTCPInstance->addStreamSocket(dests->tcpSocketNum, dests->rtcpChannelId); fRTCPInstance->setSpecificRRHandler(dests->tcpSocketNum, dests->rtcpChannelId, rtcpRRHandler, rtcpRRHandlerClientData); } } else { // Tell the RTP and RTCP 'groupsocks' about this destination // (in case they don't already have it): if (fRTPgs != NULL) fRTPgs->addDestination(dests->addr, dests->rtpPort); if (fRTCPgs != NULL) fRTCPgs->addDestination(dests->addr, dests->rtcpPort); if (fRTCPInstance != NULL) { fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr, dests->rtcpPort, rtcpRRHandler, rtcpRRHandlerClientData); } } if (!fAreCurrentlyPlaying && fMediaSource != NULL) { if (fRTPSink != NULL) { fRTPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); fAreCurrentlyPlaying = True; } else if (fUDPSink != NULL) { fUDPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); fAreCurrentlyPlaying = True; } } }
void addFaceSubstreams0(void*) { int portCounter = 0; for (int j = 0; j < cubemap->getEyesCount(); j++) { Cubemap* eye = cubemap->getEye(j); for (int i = 0; i < eye->getFacesCount(); i++) { faceStreams.push_back(FrameStreamState()); FrameStreamState* state = &faceStreams.back(); state->content = eye->getFace(i)->getContent(); Port rtpPort(FACE0_RTP_PORT_NUM + portCounter); portCounter += 2; Groupsock* rtpGroupsock = new Groupsock(*env, destinationAddress, rtpPort, TTL); //rtpGroupsock->multicastSendOnly(); // we're a SSM source setReceiveBufferTo(*env, rtpGroupsock->socketNum(), bufferSize); // Create a 'H264 Video RTP' sink from the RTP 'groupsock': state->sink = H264VideoRTPSink::createNew(*env, rtpGroupsock, 96); ServerMediaSubsession* subsession = PassiveServerMediaSubsession::createNew(*state->sink); cubemapSMS->addSubsession(subsession); RawPixelSource* source = RawPixelSource::createNew(*env, state->content, avgBitRate); source->setOnSentNALU (boost::bind(&onSentNALU, _1, _2, _3, j, i)); source->setOnEncodedFrame(boost::bind(&onEncodedFrame, _1, j, i)); state->source = H264VideoStreamDiscreteFramer::createNew(*env, source); state->sink->startPlaying(*state->source, NULL, NULL); std::cout << "Streaming face " << i << " (" << ((j == 0) ? "left" : "right") << ") on port " << ntohs(rtpPort.num()) << " ..." << std::endl; } } announceStream(rtspServer, cubemapSMS, cubemapStreamName); }
void StreamState::endPlaying(Destinations* dests) { if (dests->isTCP) { if (fRTPSink != NULL) { fRTPSink->removeStreamSocket(dests->tcpSocketNum, dests->rtpChannelId); } if (fRTCPInstance != NULL) { fRTCPInstance->removeStreamSocket(dests->tcpSocketNum, dests->rtcpChannelId); fRTCPInstance->setSpecificRRHandler(dests->tcpSocketNum, dests->rtcpChannelId, NULL, NULL); } } else { // Tell the RTP and RTCP 'groupsocks' to stop using these destinations: if (fRTPgs != NULL) fRTPgs->removeDestination(dests->addr, dests->rtpPort); if (fRTCPgs != NULL) fRTCPgs->removeDestination(dests->addr, dests->rtcpPort); if (fRTCPInstance != NULL) { fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr, dests->rtcpPort, NULL, NULL); } } }
void OnDemandServerMediaSubsession ::getStreamParameters(unsigned clientSessionId, netAddressBits clientAddress, Port const& clientRTPPort, Port const& clientRTCPPort, int tcpSocketNum, unsigned char rtpChannelId, unsigned char rtcpChannelId, netAddressBits& destinationAddress, u_int8_t& /*destinationTTL*/, Boolean& isMulticast, Port& serverRTPPort, Port& serverRTCPPort, void*& streamToken) { if (destinationAddress == 0) destinationAddress = clientAddress; struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress; isMulticast = False; if (fLastStreamToken != NULL && fReuseFirstSource) { // Special case: Rather than creating a new 'StreamState', // we reuse the one that we've already created: serverRTPPort = ((StreamState*)fLastStreamToken)->serverRTPPort(); serverRTCPPort = ((StreamState*)fLastStreamToken)->serverRTCPPort(); ++((StreamState*)fLastStreamToken)->referenceCount(); streamToken = fLastStreamToken; } else { // Normal case: Create a new media source: unsigned streamBitrate; FramedSource* mediaSource = createNewStreamSource(clientSessionId, streamBitrate); // Create 'groupsock' and 'sink' objects for the destination, // using previously unused server port numbers: RTPSink* rtpSink; BasicUDPSink* udpSink; Groupsock* rtpGroupsock; Groupsock* rtcpGroupsock; portNumBits serverPortNum; if (clientRTCPPort.num() == 0) { // We're streaming raw UDP (not RTP). Create a single groupsock: NoReuse dummy(envir()); // ensures that we skip over ports that are already in use for (serverPortNum = fInitialPortNum; ; ++serverPortNum) { struct in_addr dummyAddr; dummyAddr.s_addr = 0; serverRTPPort = serverPortNum; rtpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPort, 255); if (rtpGroupsock->socketNum() >= 0) break; // success } rtcpGroupsock = NULL; rtpSink = NULL; udpSink = BasicUDPSink::createNew(envir(), rtpGroupsock); } else { // Normal case: We're streaming RTP (over UDP or TCP). Create a pair of // groupsocks (RTP and RTCP), with adjacent port numbers (RTP port number even): NoReuse dummy(envir()); // ensures that we skip over ports that are already in use for (portNumBits serverPortNum = fInitialPortNum; ; serverPortNum += 2) { struct in_addr dummyAddr; dummyAddr.s_addr = 0; serverRTPPort = serverPortNum; rtpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPort, 255); if (rtpGroupsock->socketNum() < 0) { delete rtpGroupsock; continue; // try again } serverRTCPPort = serverPortNum+1; rtcpGroupsock = new Groupsock(envir(), dummyAddr, serverRTCPPort, 255); if (rtcpGroupsock->socketNum() < 0) { delete rtpGroupsock; delete rtcpGroupsock; continue; // try again } break; // success } unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic rtpSink = createNewRTPSink(rtpGroupsock, rtpPayloadType, mediaSource); udpSink = NULL; } // Turn off the destinations for each groupsock. They'll get set later // (unless TCP is used instead): if (rtpGroupsock != NULL) rtpGroupsock->removeAllDestinations(); if (rtcpGroupsock != NULL) rtcpGroupsock->removeAllDestinations(); if (rtpGroupsock != NULL) { // Try to use a big send buffer for RTP - at least 0.1 second of // specified bandwidth and at least 50 KB unsigned rtpBufSize = streamBitrate * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes if (rtpBufSize < 50 * 1024) rtpBufSize = 50 * 1024; increaseSendBufferTo(envir(), rtpGroupsock->socketNum(), rtpBufSize); } // Set up the state of the stream. The stream will get started later: streamToken = fLastStreamToken = new StreamState(*this, serverRTPPort, serverRTCPPort, rtpSink, udpSink, streamBitrate, mediaSource, rtpGroupsock, rtcpGroupsock); } // Record these destinations as being for this client session id: Destinations* destinations; if (tcpSocketNum < 0) { // UDP destinations = new Destinations(destinationAddr, clientRTPPort, clientRTCPPort); } else { // TCP destinations = new Destinations(tcpSocketNum, rtpChannelId, rtcpChannelId); } fDestinationsHashTable->Add((char const*)clientSessionId, destinations); }
int CMPIPTV_RTSP::OpenConnection(void) { this->logger.Log(LOGGER_INFO, METHOD_START_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME); this->isRtspSessionSetup = false; // LIVE555 works with char, not with TCHAR char *tempRtspUrl = ConvertToMultiByte(this->rtspUrl); if (tempRtspUrl == NULL) { return STATUS_ERROR; } // start LIVE555 worker thread this->rtspSchedulerThreadHandle = CreateThread( NULL, // default security attributes 0, // use default stack size &CMPIPTV_RTSP::RtspSchedulerWorker, // thread function name this, // argument to thread function 0, // use default creation flags &this->rtspSchedulerThreadId); // returns the thread identifier if (this->rtspSchedulerThreadHandle == NULL) { this->logger.Log(LOGGER_ERROR, _T("%s: %s: failed to create RTSP scheduler thread, error = %i"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, GetLastError()); return STATUS_ERROR; } this->rtspClient = MPRTSPClient::createNew(this, *this->rtspEnvironment, tempRtspUrl); FREE_MEM(tempRtspUrl); if ( this->rtspClient == NULL || SendRtspCommand(METHOD_OPEN_CONNECTION_NAME, _T("OPTIONS")) != STATUS_OK || SendRtspCommand(METHOD_OPEN_CONNECTION_NAME, _T("DESCRIBE")) != STATUS_OK ) { CloseConnection(); return STATUS_ERROR; } this->rtspSession = MediaSession::createNew(*this->rtspEnvironment, this->rtspResponseResultString); if (this->rtspSession == NULL || !this->rtspSession->hasSubsessions()) { this->LogRtspMessage(LOGGER_ERROR, METHOD_OPEN_CONNECTION_NAME, this->rtspSession == NULL ? _T("failed to create session") : _T("session doesn't have sub-sessions")); CloseConnection(); return STATUS_ERROR; } // Setup the RTP source for the session. Only one sub-session expected/supported. MediaSubsessionIterator iter(*this->rtspSession); MediaSubsession *subsession = NULL; FramedSource *rtspSource = NULL; while ((subsession = iter.next()) != NULL) { #ifdef _MBCS TCHAR *subSessionName = ConvertToMultiByteA(subsession->mediumName()); TCHAR *subSessionCodecName = ConvertToMultiByteA(subsession->codecName()); #else TCHAR *subSessionName = ConvertToUnicodeA(subsession->mediumName()); TCHAR *subSessionCodecName = ConvertToUnicodeA(subsession->codecName()); #endif if (_tcsncicmp(subSessionName, _T("video"), 5) != 0 || _tcsncicmp(subSessionCodecName, _T("MP2T"), 4) != 0) { TCHAR *message = FormatString(_T("sub-session medium or codec not supported, medium = %s, codec = %s"), subSessionName, subSessionCodecName); this->LogRtspMessage(LOGGER_ERROR, METHOD_OPEN_CONNECTION_NAME, message); FREE_MEM(message); FREE_MEM(subSessionName); FREE_MEM(subSessionCodecName); continue; } // If a client port is configured, find a free pair of ports in the range. // The first port is used for RTP; the second port is used for RTCP. Once // we find one free port, we assume the next one is also free. if (this->rtspRtpClientPortRangeStart > 0) { struct in_addr destinationAddress; destinationAddress.s_addr = our_inet_addr("127.0.0.1"); unsigned int port = this->rtspRtpClientPortRangeStart; Groupsock *groupsock = NULL; do { this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: RTP client port %u"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, port); // special construction force not reuse same UDP port { NoReuse noReuse(*this->rtspEnvironment); groupsock = new Groupsock(*this->rtspEnvironment, destinationAddress, port, 1); } if (groupsock == NULL || groupsock->socketNum() == -1) { this->logger.Log(LOGGER_WARNING, _T("%s: %s: RTP client port %u occupied, trying next even port"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, port); port += 2; if (groupsock != NULL) { delete groupsock; groupsock = NULL; } } } while ((groupsock == NULL) && (port <= this->rtspRtpClientPortRangeEnd)); // Did we find a free port? If not, we fall back to a random port chosen // by LIVE555. if (groupsock != NULL) { delete groupsock; groupsock = NULL; subsession->setClientPortNum(port); } } if (!subsession->initiate() || subsession->rtpSource() == NULL) { TCHAR *message = FormatString(_T("failed to create receiver for sub-session, medium = %s, codec = %s"), subSessionName, subSessionCodecName); this->LogRtspMessage(LOGGER_ERROR, METHOD_OPEN_CONNECTION_NAME, message); FREE_MEM(message); FREE_MEM(subSessionName); FREE_MEM(subSessionCodecName); continue; } this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: created receiver for sub-session, medium = %s, codec = %s"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName, subSessionCodecName); FREE_MEM(subSessionName); FREE_MEM(subSessionCodecName); // set session ID, doesn't matter what subsession->setSessionId(subsession->mediumName()); // because we're saving the incoming data, rather than playing // it in real time, allow an especially large time threshold // for reordering misordered incoming packets: subsession->rtpSource()->setPacketReorderingThresholdTime(1000000); // 1 second // set the RTP source's OS socket buffer size as appropriate int socketNum = subsession->rtpSource()->RTPgs()->socketNum(); unsigned int currentBufferSize = getReceiveBufferSize(*this->rtspEnvironment, socketNum); if (this->defaultBufferSize > currentBufferSize) { setReceiveBufferTo(*this->rtspEnvironment, socketNum, this->defaultBufferSize); unsigned setBufferSize = getReceiveBufferSize(*this->rtspEnvironment, socketNum); if (setBufferSize == this->defaultBufferSize) { this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: set buffer size for sub-session, previous size = %i, requested size = %i, current size = %i"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName, currentBufferSize, this->defaultBufferSize, setBufferSize); } else { this->logger.Log(LOGGER_WARNING, _T("%s: %s: failed to set buffer size for sub-session, previous size = %i, requested size = %i, current size = %i"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName, currentBufferSize, this->defaultBufferSize, setBufferSize); } } if (SendRtspCommand(METHOD_OPEN_CONNECTION_NAME, _T("SETUP"), subsession) != STATUS_OK) { CloseConnection(); return STATUS_ERROR; } rtspSource = subsession->rtpSource(); break; } // If we don't have an RTSP source then we can't continue. if (rtspSource == NULL) { CloseConnection(); return STATUS_ERROR; } this->isRtspSessionSetup = true; if (SendRtspCommand(METHOD_OPEN_CONNECTION_NAME, _T("PLAY")) != STATUS_OK) { CloseConnection(); return STATUS_ERROR; } // create UDP socket and start playing struct in_addr destinationAddress; destinationAddress.s_addr = our_inet_addr("127.0.0.1"); unsigned int port = this->rtspUdpPortRangeStart; do { this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: UDP port %u"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, port); // special construction force not reuse same UDP port { NoReuse noReuse(*this->rtspEnvironment); this->rtspUdpGroupsock = new Groupsock(*this->rtspEnvironment, destinationAddress, port, 1); } if (this->rtspUdpGroupsock == NULL || this->rtspUdpGroupsock->socketNum() == -1) { this->logger.Log(LOGGER_WARNING, _T("%s: %s: UDP port %u occupied, trying another port"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, port); port++; if (this->rtspUdpGroupsock != NULL) { delete this->rtspUdpGroupsock; this->rtspUdpGroupsock = NULL; } } } while ((this->rtspUdpGroupsock == NULL) && (port <= this->rtspUdpPortRangeEnd)); if (this->rtspUdpGroupsock == NULL) { this->logger.Log(LOGGER_ERROR, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("failed to create UDP socket, no free port")); CloseConnection(); return STATUS_ERROR; } this->rtspUdpSink = BasicUDPSink::createNew(*this->rtspEnvironment, this->rtspUdpGroupsock, this->rtspUdpSinkMaxPayloadSize); if (this->rtspUdpSink == NULL) { this->logger.Log(LOGGER_ERROR, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("failed to create UDP sink")); CloseConnection(); return STATUS_ERROR; } if (!this->rtspUdpSink->startPlaying(*rtspSource, NULL, NULL)) { this->LogRtspMessage(LOGGER_ERROR, METHOD_OPEN_CONNECTION_NAME, _T("failed to start UDP sink")); CloseConnection(); return STATUS_ERROR; } this->logger.Log(LOGGER_INFO, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("streaming started")); // create a UDP connection to the local stream TCHAR *url = FormatString(_T("udp://@127.0.0.1:%u"), port); if ( url == NULL || this->CMPIPTV_UDP::ParseUrl(url, NULL) != STATUS_OK || this->CMPIPTV_UDP::OpenConnection() != STATUS_OK ) { FREE_MEM(url); this->logger.Log(LOGGER_INFO, METHOD_END_FAIL_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME); CloseConnection(); return STATUS_ERROR; } FREE_MEM(url); this->logger.Log(LOGGER_INFO, METHOD_END_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME); return STATUS_OK; }