char const* OnDemandServerMediaSubsession::sdpLines() { FUN_IN(); if (fSDPLines == NULL) { // We need to construct a set of SDP lines that describe this // subsession (as a unicast stream). To do so, we first create // dummy (unused) source and "RTPSink" objects, // whose parameters we use for the SDP lines: unsigned estBitrate; FramedSource* inputSource = createNewStreamSource(0, estBitrate); if (inputSource == NULL) return NULL; // file not found struct in_addr dummyAddr; dummyAddr.s_addr = 0; Groupsock dummyGroupsock(envir(), dummyAddr, 0, 0); unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic RTPSink* dummyRTPSink = createNewRTPSink(&dummyGroupsock, rtpPayloadType, inputSource); if (dummyRTPSink != NULL && dummyRTPSink->estimatedBitrate() > 0) estBitrate = dummyRTPSink->estimatedBitrate(); setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate); Medium::close(dummyRTPSink); closeStreamSource(inputSource); } FUN_OUT(); return fSDPLines; }
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; /* :TODO:2014/9/12 13:17:28:Sean: added*/ printf("client requests unicast 0x%x\n", clientAddress); /* :TODO:End--- */ } /* :TODO:2014/9/12 13:17:28:Sean: added no multicastAddress*/ if (isMulticast) { // destinationAddress = multicastAddress; printf("client requests mulicast, port %d\n", fInitialPortNum); } /* :TODO:End--- */ 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 = NULL; BasicUDPSink* udpSink = NULL; Groupsock* rtpGroupsock = NULL; Groupsock* rtcpGroupsock = NULL; if (clientRTPPort.num() != 0 || tcpSocketNum >= 0) { // Normal case: Create destinations 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 } 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). // (If we're multiplexing RTCP and RTP over the same port number, it can be odd or even.) NoReuse dummy(envir()); // ensures that we skip over ports that are already in use for (portNumBits serverPortNum = fInitialPortNum; ; ++serverPortNum) { 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 } if (fMultiplexRTCPWithRTP) { // Use the RTP 'groupsock' object for RTCP as well: serverRTCPPort = serverRTPPort; rtcpGroupsock = rtpGroupsock; } else { // Create a separate 'groupsock' object (with the next (odd) port number) for RTCP: serverRTCPPort = ++serverPortNum; 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); if (rtpSink != NULL && rtpSink->estimatedBitrate() > 0) streamBitrate = rtpSink->estimatedBitrate(); } // 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/*Sean added*/, fParentSession->envir()); } // 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); }