int CMPIPTV_RTSP::SendRtspCommand(const TCHAR *method, const TCHAR *command, MediaSubsession *subsession) { this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: send %s command"), PROTOCOL_IMPLEMENTATION_NAME, method, command); ResetEvent(this->rtspResponseEvent); if (_tcscmp(command, _T("OPTIONS")) == 0) { this->rtspClient->sendOptionsCommand(&CMPIPTV_RTSP::OnRtspResponseReceived); } else if (_tcscmp(command, _T("DESCRIBE")) == 0) { this->rtspClient->sendDescribeCommand(&CMPIPTV_RTSP::OnRtspResponseReceived); } else if (_tcscmp(command, _T("SETUP")) == 0) { this->rtspClient->sendSetupCommand(*subsession, &CMPIPTV_RTSP::OnRtspResponseReceived); } else if (_tcscmp(command, _T("PLAY")) == 0) { this->rtspClient->sendPlayCommand(*this->rtspSession, &CMPIPTV_RTSP::OnRtspResponseReceived); } else if (_tcscmp(command, _T("TEARDOWN")) == 0) { this->rtspClient->sendTeardownCommand(*this->rtspSession, &CMPIPTV_RTSP::OnRtspResponseReceived); } else { return STATUS_ERROR; } if (WaitForSingleObject(this->rtspResponseEvent, this->rtspCommandResponseTimeout) == WAIT_TIMEOUT) { this->logger.Log(LOGGER_ERROR, _T("%s: %s: %s command timed out"), PROTOCOL_IMPLEMENTATION_NAME, method, command); return STATUS_ERROR; } if (this->rtspResponseResultCode != 0) { #ifdef _MBCS TCHAR *convertedRtspResponse = ConvertToMultiByteA(&this->rtspResponseResultString[0]); #else TCHAR *convertedRtspResponse = ConvertToUnicodeA(&this->rtspResponseResultString[0]); #endif this->logger.Log(LOGGER_ERROR, _T("%s: %s: %s command failed, code = %i, response = %s"), PROTOCOL_IMPLEMENTATION_NAME, method, command, this->rtspResponseResultCode, (convertedRtspResponse == NULL) ? _T("unable to get message") : convertedRtspResponse); FREE_MEM(convertedRtspResponse); return STATUS_ERROR; } #ifdef _MBCS TCHAR *convertedRtspResponse = ConvertToMultiByteA(&this->rtspResponseResultString[0]); #else TCHAR *convertedRtspResponse = ConvertToUnicodeA(&this->rtspResponseResultString[0]); #endif this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: %s command succeeded, response = %s"), PROTOCOL_IMPLEMENTATION_NAME, method, command, (convertedRtspResponse == NULL) ? _T("unable to get message") : convertedRtspResponse); FREE_MEM(convertedRtspResponse); return STATUS_OK; }
void CMPIPTV_RTSP::LogFullRtspMessage(unsigned int loggerLevel, const TCHAR* messagePrefix, const char *message) { #ifdef _MBCS TCHAR *convertedRtspMessage = ConvertToMultiByteA(message); #else TCHAR *convertedRtspMessage = ConvertToUnicodeA(message); #endif this->logger.Log(loggerLevel, _T("%s%s %s"), messagePrefix, (convertedRtspMessage == NULL) ? _T(",") : _T(":"), (convertedRtspMessage == NULL) ? _T("unable to get message") : convertedRtspMessage); FREE_MEM(convertedRtspMessage); }
void CMPIPTV_RTSP::LogRtspMessage(unsigned int loggerLevel, const TCHAR *method, const TCHAR *message) { const char *lastRtspMessage = this->rtspEnvironment->getResultMsg(); #ifdef _MBCS TCHAR *convertedRtspMessage = ConvertToMultiByteA(lastRtspMessage); #else TCHAR *convertedRtspMessage = ConvertToUnicodeA(lastRtspMessage); #endif this->logger.Log(loggerLevel, _T("%s: %s: %s, %s"), PROTOCOL_IMPLEMENTATION_NAME, method, message, (convertedRtspMessage == NULL) ? _T("unable to get message") : convertedRtspMessage); FREE_MEM(convertedRtspMessage); }
char *CMPIPTV_RTSP::GetLastRtspMessageA(void) { return ConvertToMultiByteA(this->rtspEnvironment->getResultMsg()); }
int CMPIPTV_RTSP::OpenConnection(void) { this->logger.Log(LOGGER_INFO, METHOD_START_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME); int result = STATUS_OK; this->rtspClient = RTSPClient::createNew(*this->rtspEnvironment); result |= (this->rtspClient == NULL); if (result == STATUS_OK) { // RTSPClient works with char, not with TCHAR char *tempRtspUrl = ConvertToMultiByte(this->rtspUrl); result |= (tempRtspUrl == NULL); if (result == STATUS_OK) { char* optionsResult = this->rtspClient->sendOptionsCmd(tempRtspUrl, NULL, NULL, NULL, this->receiveDataTimeout / 2000); result |= (optionsResult == NULL); if (result != STATUS_OK) { TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("error occured while sending OPTIONS command")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("OPTIONS result")); this->LogFullRtspMessage(LOGGER_VERBOSE, message, optionsResult); FREE_MEM(message); char *describeResult = this->rtspClient->describeURL(tempRtspUrl, NULL, FALSE, this->receiveDataTimeout / 2000); result |= (describeResult == NULL); if (result != STATUS_OK) { TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("error occured while sending DESCRIBE command")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("DESCRIBE result")); this->LogFullRtspMessage(LOGGER_VERBOSE, message, describeResult); FREE_MEM(message); this->rtspSession = MediaSession::createNew(*this->rtspEnvironment, describeResult); result |= (this->rtspSession == NULL); if (result != STATUS_OK) { TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("error occured while creating new session")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { result |= (!this->rtspSession->hasSubsessions()); if (result != STATUS_OK) { this->logger.Log(LOGGER_ERROR, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("session doesn't have subsessions")); } else { // Then, setup the "RTPSource"s for the session: MediaSubsessionIterator iter(*this->rtspSession); MediaSubsession *subsession = NULL; while ((result == STATUS_OK) && ((subsession = iter.next()) != NULL)) { char *tempSubSessionName = (char *)subsession->mediumName(); char *tempSubSessionCodecName = (char *)subsession->codecName(); #ifdef _MBCS TCHAR *subSessionName = ConvertToMultiByteA(tempSubSessionName); TCHAR *subSessionCodecName = ConvertToMultiByteA(tempSubSessionCodecName); #else TCHAR *subSessionName = ConvertToUnicodeA(tempSubSessionName); TCHAR *subSessionCodecName = ConvertToUnicodeA(tempSubSessionCodecName); #endif if (!subsession->initiate()) { result = STATUS_ERROR; TCHAR *message = FormatString(_T("%s: %s: unable to create receiver for subsession '%s', codec '%s'"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName, subSessionCodecName); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: created receiver for subsession '%s', codec '%s'"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName, subSessionCodecName); // set session ID, doesn't matter what subsession->sessionId = tempSubSessionName; if (subsession->rtpSource() != NULL) { // because we're saving the incoming data, rather than playing // it in real time, allow an especially large time threshold // (1 second) for reordering misordered incoming packets: unsigned const thresh = 1000000; // 1 second subsession->rtpSource()->setPacketReorderingThresholdTime(thresh); // 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 subsession '%s' successful, previous size: %i, requested size: %i, current size: %i"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName, currentBufferSize, this->defaultBufferSize, setBufferSize); } else { result = STATUS_ERROR; this->logger.Log(LOGGER_ERROR, _T("%s: %s: set buffer size for subsession '%s' failed, previous size: %i, requested size: %i, current size: %i"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName, currentBufferSize, this->defaultBufferSize, setBufferSize); } } if (_tcsncicmp(subSessionName, _T("audio"), 5) == 0) { // audio this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: audio subsession '%s'"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName); result |= (!rtspClient->setupMediaSubsession(*subsession)); if (result != STATUS_OK) { // error occured TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("error while setup subsession")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { this->logger.Log(LOGGER_WARNING, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("subsession audio codec not supported")); } } else if (_tcsncicmp(subSessionName, _T("video"), 5) == 0) { // video this->logger.Log(LOGGER_VERBOSE, _T("%s: %s: video subsession '%s'"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName); result |= (!rtspClient->setupMediaSubsession(*subsession)); if (result != STATUS_OK) { // error occured TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("error while setup subsession")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { if (_tcsncicmp(subSessionCodecName, _T("MP2T"), 4) == 0) { // MPEG2 Transport Stream // set new RTSP source this->rtspSource = subsession->rtpSource(); if (subsession->rtcpInstance() != NULL) { this->logger.Log(LOGGER_VERBOSE, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("set subsession 'Bye' handler")); subsession->rtcpInstance()->setByeHandler(SubsessionByeHandler, this); } } else if (_tcsncicmp(subSessionCodecName, _T("H264"), 4) == 0) { // H264 codec, HD TV this->logger.Log(LOGGER_ERROR, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("H264 not supported")); result = STATUS_ERROR; } else { // SD TV this->logger.Log(LOGGER_ERROR, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("other subsession video codec than MP2T not supported")); result = STATUS_ERROR; } } } else { this->logger.Log(LOGGER_WARNING, _T("%s: %s: unknown subsession '%s', ignored"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName); } } else { this->logger.Log(LOGGER_WARNING, _T("%s: %s: subsession '%s' doesn't have RTP source"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, subSessionName); } } // free subsession name and codec name FREE_MEM(subSessionName); FREE_MEM(subSessionCodecName); } // we should have some RTSP source result |= (this->rtspSource == NULL); if (result == STATUS_OK) { result |= (!this->rtspClient->playMediaSession(*this->rtspSession)); if (result != STATUS_OK) { // error occured TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("error while playing session")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { // 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->rtspUdpGroupsock = new Groupsock(*this->rtspEnvironment, destinationAddress, port, 1); } if (this->rtspUdpGroupsock->socketNum() == (-1)) { this->logger.Log(LOGGER_ERROR, _T("%s: %s: UDP port %u occupied, trying another port"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, port); port++; delete this->rtspUdpGroupsock; this->rtspUdpGroupsock = NULL; } } while ((this->rtspUdpGroupsock == NULL) && (port <= this->rtspUdpPortRangeEnd)); result |= (this->rtspUdpGroupsock == NULL); if (result != STATUS_OK) { this->logger.Log(LOGGER_ERROR, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("cannot create UDP sink, no free port")); } else { this->rtspUdpSink = BasicUDPSink::createNew(*this->rtspEnvironment, this->rtspUdpGroupsock, this->rtspUdpSinkMaxPayloadSize); result |= (this->rtspUdpSink == NULL); if (result != STATUS_OK) { TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("cannot create UDP sink")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } else { if (this->rtspUdpSink->startPlaying(*this->rtspSource, NULL, NULL)) { this->logger.Log(LOGGER_INFO, METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("playing started")); // now create UDP connection TCHAR *url = FormatString(_T("udp://@127.0.0.1:%u"), port); result |= (url == NULL); if (result == STATUS_OK) { // parse UDP url // ParseURL calls ClearSession and IsConnected must return FALSE // in another case will be current RTSP connection closed result = this->CMPIPTV_UDP::ParseUrl(url, NULL); if (result == STATUS_OK) { // connect to UDP url result = this->CMPIPTV_UDP::OpenConnection(); } } FREE_MEM(url); } else { result = STATUS_ERROR; TCHAR *message = FormatString(METHOD_MESSAGE_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, _T("error occured while starting playing")); this->LogRtspMessage(LOGGER_ERROR, message); FREE_MEM(message); } } } } } } } } } if (optionsResult != NULL) { delete[] optionsResult; optionsResult = NULL; } } FREE_MEM(tempRtspUrl); } if (result == STATUS_OK) { // start winsock 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) { // thread not created result = STATUS_ERROR; this->logger.Log(LOGGER_ERROR, _T("%s: %s: cannot create RTSP scheduler thread, error: %i"), PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME, GetLastError()); } } if (result != STATUS_OK) { // if failed opening connection, than close connection this->CloseConnection(); } this->logger.Log(LOGGER_INFO, (result == STATUS_OK) ? METHOD_END_FORMAT : METHOD_END_FAIL_FORMAT, PROTOCOL_IMPLEMENTATION_NAME, METHOD_OPEN_CONNECTION_NAME); return (result == STATUS_OK) ? STATUS_OK : STATUS_ERROR; }
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; }