QTSS_Error ProcessRTSPRequest(QTSS_StandardRTSP_Params* inParams)
{
    QTSS_RTSPMethod* theMethod = NULL;
    UInt32 theMethodLen = 0;
    if ((QTSS_GetValuePtr(inParams->inRTSPRequest, qtssRTSPReqMethod, 0,
            (void**)&theMethod, &theMethodLen) != QTSS_NoErr) || (theMethodLen != sizeof(QTSS_RTSPMethod)))
    {
        Assert(0);
        return QTSS_RequestFailed;
    }
    
    switch (*theMethod)
    {
        case qtssDescribeMethod:
            return DoDescribe(inParams);
        case qtssSetupMethod:
            return DoSetup(inParams);
        case qtssPlayMethod:
            return DoPlay(inParams);
        case qtssTeardownMethod:
            // Tell the server that this session should be killed, and send a TEARDOWN response
            (void)QTSS_Teardown(inParams->inClientSession);
            (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0);
            break;
        case qtssPauseMethod:
            (void)QTSS_Pause(inParams->inClientSession);
            (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0);
            break;
        default:
            break;
    }           

    return QTSS_NoErr;
}
QTSS_Error ProcessRTSPRequest(QTSS_StandardRTSP_Params* inParams)
{
    QTSS_RTSPMethod* theMethod = NULL;

	UInt32 theLen = 0;
    if ((QTSS_GetValuePtr(inParams->inRTSPRequest, qtssRTSPReqMethod, 0,
            (void**)&theMethod, &theLen) != QTSS_NoErr) || (theLen != sizeof(QTSS_RTSPMethod)))
    {
        Assert(0);
        return QTSS_RequestFailed;
    }

    if (*theMethod == qtssDescribeMethod)
        return DoDescribe(inParams);
    if (*theMethod == qtssSetupMethod)
        return DoSetup(inParams);
        
    RTPSessionOutput** theOutput = NULL;
    QTSS_Error theErr = QTSS_GetValuePtr(inParams->inClientSession, sOutputAttr, 0, (void**)&theOutput, &theLen);
    if ((theErr != QTSS_NoErr) || (theLen != sizeof(RTPSessionOutput*))) // a broadcaster push session
    {   if (*theMethod == qtssPlayMethod || *theMethod == qtssRecordMethod)
            return DoPlay(inParams, NULL);
        else
            return QTSS_RequestFailed;
    }

    switch (*theMethod)
    {
        case qtssPlayMethod:
            return DoPlay(inParams, (*theOutput)->GetReflectorSession());
        case qtssTeardownMethod:
            // Tell the server that this session should be killed, and send a TEARDOWN response
            (void)QTSS_Teardown(inParams->inClientSession);
            (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0);
            break;
        case qtssPauseMethod:
            (void)QTSS_Pause(inParams->inClientSession);
            (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0);
            break;
        default:
            break;
    }           
    return QTSS_NoErr;
}
Exemple #3
0
QTSS_Error  DoRequestPostProcessing(ProxyClientInfo* inProxyClientInfo, QTSS_RTSPRequestObject inRequest,
                                    QTSS_ClientSessionObject inClientSession)
{
    
    QTSS_RTSPMethod* theMethod = NULL;
    UInt32 theLen = 0;
    QTSS_Error theErr = QTSS_GetValuePtr(inRequest, qtssRTSPReqMethod, 0, (void**)&theMethod, &theLen);
    Assert(theErr == QTSS_NoErr);

    char theTransportHeaderBuf[128];
    StrPtrLen theTransportHeader(theTransportHeaderBuf, 0);

    StrPtrLen theSessionID;
    theErr = QTSS_GetValuePtr(inClientSession, qtssCliSesRTSPSessionID, 0, (void**)&theSessionID.Ptr, &theSessionID.Len);
    Assert(theErr == QTSS_NoErr);
    
    StrPtrLen theResponse(inProxyClientInfo->GetRTSPClient()->GetResponse(), inProxyClientInfo->GetRTSPClient()->GetResponseLen());

    if ((*theMethod == qtssSetupMethod) &&
        (inProxyClientInfo->GetRTSPClient()->GetStatus() == 200))
    {
        ProxyDemuxerTask* thisStreamsDemuxer = inProxyClientInfo->GetLastDemuxerTask();
        thisStreamsDemuxer->SetOriginServerPort(inProxyClientInfo->GetRTSPClient()->GetServerPort());
        
        //
        // Build a new Transport header. This should basically be exactly what the
        // server would be sending back if the proxy module wasn't generating the response
        UInt16 theSvrRTPPort = 0;
        UInt16 theCliRTPPort = 0;
        UInt32 theLen = sizeof(theSvrRTPPort);
        theErr = QTSS_GetValue(thisStreamsDemuxer->GetStream(), qtssRTPStrSvrRTPPort, 0, &theSvrRTPPort, &theLen);
        Assert(theErr == QTSS_NoErr);
        theErr = QTSS_GetValue(thisStreamsDemuxer->GetStream(), qtssRTPStrClientRTPPort, 0, &theCliRTPPort, &theLen);
        Assert(theErr == QTSS_NoErr);
        
        char theIPAddrStr[20];
        theLen = 20;
        theErr = QTSS_GetValue(inClientSession, qtssCliRTSPSessLocalAddrStr, 0, &theIPAddrStr[0], &theLen);
        Assert(theErr == QTSS_NoErr);
        theIPAddrStr[theLen] = '\0';
        
        qtss_sprintf(theTransportHeader.Ptr, "Transport: RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d;source=%s\r\n",
            theCliRTPPort, theCliRTPPort + 1, theSvrRTPPort, theSvrRTPPort + 1, theIPAddrStr);
        
        theTransportHeader.Len = ::strlen(theTransportHeader.Ptr);
    }
    else if ((*theMethod == qtssPlayMethod) &&
            (inProxyClientInfo->GetRTSPClient()->GetStatus() == 200))
    {
        //
        // The client session needs to know that we are entering the playing state.
        // Otherwise, when we write RTP packet data to the QTSS_RTPStreamObjects,
        // the server won't really be able to figure out what to do with the packets.
        theErr = QTSS_Play(inClientSession, inRequest, 0);
        if (theErr != QTSS_NoErr)
        {
            Assert(theErr == QTSS_RequestFailed);
            return theErr;
        }
    }
    else if ((*theMethod == qtssPauseMethod) &&
            (inProxyClientInfo->GetRTSPClient()->GetStatus() == 200))
    {
        //
        // Same thing as above, just let the server know that we are no longer playing
        theErr = QTSS_Pause(inClientSession);
        Assert(theErr == QTSS_NoErr);
    }
    //
    // Build our ioVec with the new response
    // When building the iovec used for the response, we need to leave the first
    // iovec in the array empty, per QTSS API conventions.
    iovec theNewResponse[7];
    theNewResponse[0].iov_len = 0;
    UInt32 totalResponseLen = 0;

    //
    // Internally, the server keeps an RTSP Session ID for this QTSS_ClientSessionObject.
    // We need to replace the one the upstream server has given us with this server's
    // RTSP Session ID. Otherwise, when the server receives the next RTSP request,
    // this server will not be able to map the RTSP session ID properly. 
    UInt32 theNumVecs = ReplaceSessionAndTransportHeaders(&theResponse, &theNewResponse[1], &theSessionID, &theTransportHeader, &totalResponseLen);
    theNumVecs++; // Take into account that the first one is empty
    //
    // Also add in the content body of the response if there is one
    theNewResponse[theNumVecs].iov_base = inProxyClientInfo->GetRTSPClient()->GetContentBody();
    theNewResponse[theNumVecs].iov_len = inProxyClientInfo->GetRTSPClient()->GetContentLength();
    totalResponseLen += theNewResponse[theNumVecs].iov_len;
    theNumVecs++;
    
    UInt32 lenWritten = 0;
    theErr = QTSS_WriteV(inRequest, theNewResponse, theNumVecs, totalResponseLen, &lenWritten);
    Assert(lenWritten == totalResponseLen);
    Assert(theErr == QTSS_NoErr);
    
    return QTSS_NoErr;
}
QTSS_Error SendPackets(QTSS_RTPSendPackets_Params* inParams)
{
    FileSession** theFile = NULL;
    UInt32 theLen = 0;
    QTSS_Error theErr = QTSS_GetValuePtr(inParams->inClientSession, sFileSessionAttr, 0, (void**)&theFile, &theLen);
    if ((theErr != QTSS_NoErr) || (theLen != sizeof(FileSession*)))
    {
        Assert( 0 );
        return QTSS_RequestFailed;
    }
    
    while (true)
    {   
        if ((*theFile)->fPacketStruct.packetData == NULL)
        {
            void* theCookie = NULL;
            Float64 theTransmitTime = (*theFile)->fFile.GetNextPacket((UInt8**)&(*theFile)->fPacketStruct.packetData, &(*theFile)->fNextPacketLen, &theCookie);
            
            //
            // Check to see if we should stop playing based on a client specified stop time
            if (((*theFile)->fStopTime != -1) && (theTransmitTime > (*theFile)->fStopTime))
            {
                // We should indeed stop playing
                (void)QTSS_Pause(inParams->inClientSession);
                inParams->outNextPacketTime = qtssDontCallSendPacketsAgain;
                return QTSS_NoErr;
            }

            //
            // Adjust transmit time based on speed
            Float64 theOffsetFromStartTime = theTransmitTime - (*theFile)->fStartTime;
            theTransmitTime = (*theFile)->fStartTime + (theOffsetFromStartTime / (*theFile)->fSpeed);
            
            (*theFile)->fStream = (QTSS_RTPStreamObject)theCookie;
            (*theFile)->fPacketStruct.packetTransmitTime = (*theFile)->fAdjustedPlayTime + ((SInt64)(theTransmitTime * 1000));
#if RTP_FILE_MODULE_DEBUGGING >= 8
            UInt16* theSeqNumPtr = (UInt16*)(*theFile)->fNextPacket;
            UInt32* theTimestampP = (UInt32*)(*theFile)->fNextPacket;
            UInt32* theTrackID = NULL;
            (void)QTSS_GetValuePtr((*theFile)->fStream, qtssRTPStrTrackID, 0, (void**)&theTrackID, &theLen);
            qtss_printf("Got packet. Seq num: %d. Timestamp: %d. TrackID: %d. Transmittime: %f\n",theSeqNumPtr[1], theTimestampP[1], *theTrackID, theTransmitTime);
#endif
        }
        
        //We are done playing all streams!
        if ((*theFile)->fPacketStruct.packetData == NULL)
        {
#if RTP_FILE_MODULE_DEBUGGING >= 8
            qtss_printf("done w all packets\n");
#endif
            inParams->outNextPacketTime = qtssDontCallSendPacketsAgain;
            return QTSS_NoErr;
        }
        //we have a packet that needs to be sent now
        Assert((*theFile)->fStream != NULL);

        // Send the packet!
        theErr =  QTSS_Write((*theFile)->fStream, &(*theFile)->fPacketStruct, (*theFile)->fNextPacketLen, NULL, qtssWriteFlagsIsRTP);

        if ( theErr == QTSS_WouldBlock )
        {   
            if ((*theFile)->fPacketStruct.packetTransmitTime == -1)
                inParams->outNextPacketTime = sFlowControlProbeInterval;    // for buffering, try me again in # MSec
            else
            {
                Assert((*theFile)->fPacketStruct.packetTransmitTime > inParams->inCurrentTime);
                inParams->outNextPacketTime = (*theFile)->fPacketStruct.packetTransmitTime - inParams->inCurrentTime;
            }
                
            return QTSS_NoErr;
        }

        (*theFile)->fPacketStruct.packetData = NULL;
    }
    Assert(0);
    return QTSS_NoErr;
}