| /********** |
| 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 <http://www.gnu.org/copyleft/lesser.html>.) |
| |
| 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-2020, Live Networks, Inc. All rights reserved |
| // A SIP client test program that opens a SIP URL argument, |
| // and extracts the data from each incoming RTP stream. |
| |
| #include "playCommon.hh" |
| #include "SIPClient.hh" |
| |
| static char* getLine(char* startOfLine) { |
| // returns the start of the next line, or NULL if none |
| for (char* ptr = startOfLine; *ptr != '\0'; ++ptr) { |
| if (*ptr == '\r' || *ptr == '\n') { |
| // We found the end of the line |
| *ptr++ = '\0'; |
| if (*ptr == '\n') ++ptr; |
| return ptr; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| SIPClient* ourSIPClient = NULL; |
| Medium* createClient(UsageEnvironment& env, char const* /*url*/, int verbosityLevel, char const* applicationName) { |
| // First, trim any directory prefixes from "applicationName": |
| char const* suffix = &applicationName[strlen(applicationName)]; |
| while (suffix != applicationName) { |
| if (*suffix == '/' || *suffix == '\\') { |
| applicationName = ++suffix; |
| break; |
| } |
| --suffix; |
| } |
| |
| extern unsigned char desiredAudioRTPPayloadFormat; |
| extern char* mimeSubtype; |
| return ourSIPClient = SIPClient::createNew(env, desiredAudioRTPPayloadFormat, mimeSubtype, verbosityLevel, applicationName); |
| } |
| |
| // The followign function is implemented, but is not used for "playSIP": |
| void assignClient(Medium* /*client*/) { |
| } |
| |
| void getOptions(RTSPClient::responseHandler* afterFunc) { |
| ourSIPClient->envir().setResultMsg("NOT SUPPORTED IN CLIENT"); |
| afterFunc(NULL, -1, strDup(ourSIPClient->envir().getResultMsg())); |
| } |
| |
| void getSDPDescription(RTSPClient::responseHandler* afterFunc) { |
| extern char* proxyServerName; |
| if (proxyServerName != NULL) { |
| // Tell the SIP client about the proxy: |
| NetAddressList addresses(proxyServerName); |
| if (addresses.numAddresses() == 0) { |
| ourSIPClient->envir() << "Failed to find network address for \"" << proxyServerName << "\"\n"; |
| } else { |
| NetAddress address = *(addresses.firstAddress()); |
| unsigned proxyServerAddress // later, allow for IPv6 ##### |
| = *(unsigned*)(address.data()); |
| extern unsigned short proxyServerPortNum; |
| if (proxyServerPortNum == 0) proxyServerPortNum = 5060; // default |
| |
| ourSIPClient->setProxyServer(proxyServerAddress, proxyServerPortNum); |
| } |
| } |
| |
| extern unsigned short desiredPortNum; |
| unsigned short clientStartPortNum = desiredPortNum; |
| if (clientStartPortNum == 0) clientStartPortNum = 8000; // default |
| ourSIPClient->setClientStartPortNum(clientStartPortNum); |
| |
| extern char const* streamURL; |
| char const* username = ourAuthenticator == NULL ? NULL : ourAuthenticator->username(); |
| char const* password = ourAuthenticator == NULL ? NULL : ourAuthenticator->password(); |
| char* result; |
| if (username != NULL && password != NULL) { |
| result = ourSIPClient->inviteWithPassword(streamURL, username, password); |
| } else { |
| result = ourSIPClient->invite(streamURL); |
| } |
| |
| int resultCode = result == NULL ? -1 : 0; |
| afterFunc(NULL, resultCode, strDup(result)); |
| } |
| |
| void setupSubsession(MediaSubsession* subsession, Boolean /*streamUsingTCP*/, Boolean /*forceMulticastOnUnspecified*/,RTSPClient::responseHandler* afterFunc) { |
| subsession->setSessionId("mumble"); // anything that's non-NULL will work |
| |
| ////////// BEGIN hack code that should really be implemented in SIPClient ////////// |
| // Parse the "Transport:" header parameters: |
| // We do not send audio, but we need port for RTCP |
| char* serverAddressStr; |
| portNumBits serverPortNum; |
| unsigned char rtpChannelId, rtcpChannelId; |
| |
| rtpChannelId = rtcpChannelId = 0xff; |
| serverPortNum = 0; |
| serverAddressStr = NULL; |
| |
| char* sdp = strDup(ourSIPClient->getInviteSdpReply()); |
| |
| char* lineStart; |
| char* nextLineStart = sdp; |
| while (1) { |
| lineStart = nextLineStart; |
| if (lineStart == NULL) { |
| break; |
| } |
| nextLineStart = getLine(lineStart); |
| |
| char* toTagStr = strDupSize(lineStart); |
| |
| if (sscanf(lineStart, "m=audio %[^/\r\n]", toTagStr) == 1) { |
| sscanf(toTagStr, "%hu", &serverPortNum); |
| } else if (sscanf(lineStart, "c=IN IP4 %[^/\r\n]", toTagStr) == 1) { |
| serverAddressStr = strDup(toTagStr); |
| } |
| delete[] toTagStr; |
| } |
| |
| if(sdp != NULL) { |
| delete[] sdp; |
| } |
| |
| delete[] subsession->connectionEndpointName(); |
| subsession->connectionEndpointName() = serverAddressStr; |
| subsession->serverPortNum = serverPortNum; |
| subsession->rtpChannelId = rtpChannelId; |
| subsession->rtcpChannelId = rtcpChannelId; |
| |
| // Set the RTP and RTCP sockets' destination address and port from the information in the SETUP response (if present): |
| netAddressBits destAddress = subsession->connectionEndpointAddress(); |
| if (destAddress != 0) { |
| subsession->setDestinations(destAddress); |
| } |
| ////////// END hack code that should really be implemented in SIPClient ////////// |
| |
| afterFunc(NULL, 0, NULL); |
| } |
| |
| void startPlayingSession(MediaSession* /*session*/, double /*start*/, double /*end*/, float /*scale*/, RTSPClient::responseHandler* afterFunc) { |
| if (ourSIPClient->sendACK()) { |
| //##### This isn't quite right, because we should really be allowing |
| //##### for the possibility of this ACK getting lost, by retransmitting |
| //##### it *each time* we get a 2xx response from the server. |
| afterFunc(NULL, 0, NULL); |
| } else { |
| afterFunc(NULL, -1, strDup(ourSIPClient->envir().getResultMsg())); |
| } |
| } |
| void startPlayingSession(MediaSession* /*session*/, const char* /*start*/, const char* /*end*/, float /*scale*/, RTSPClient::responseHandler* afterFunc) { |
| startPlayingSession(NULL,(double)0,(double)0,0,afterFunc); |
| } |
| |
| void tearDownSession(MediaSession* /*session*/, RTSPClient::responseHandler* afterFunc) { |
| if (ourSIPClient == NULL || ourSIPClient->sendBYE()) { |
| afterFunc(NULL, 0, NULL); |
| } else { |
| afterFunc(NULL, -1, strDup(ourSIPClient->envir().getResultMsg())); |
| } |
| } |
| |
| void setUserAgentString(char const* userAgentString) { |
| ourSIPClient->setUserAgentString(userAgentString); |
| } |
| |
| Boolean allowProxyServers = True; |
| Boolean controlConnectionUsesTCP = False; |
| Boolean supportCodecSelection = True; |
| char const* clientProtocolName = "SIP"; |