/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2008 Apple Inc.  All Rights Reserved.
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 *
 */
/*
    File:       QTSSCallbacks.cpp

    Contains:   Implements QTSS Callback functions.
                    
    
*/

#include "QTSSCallbacks.h"
#include "QTSSDictionary.h"
#include "QTSSStream.h"
#include "OSMemory.h"
#include "RTSPRequestInterface.h"
#include "RTPSession.h"
#include "OS.h"
#include "EventContext.h"
#include "Socket.h"
#include "QTSSFile.h"
#include "QTSSSocket.h"
#include "QTSServerInterface.h"
#include "QTSSDataConverter.h"
#include "QTSSModule.h"

#include <errno.h>

#define __QTSSCALLBACKS_DEBUG__ 0
#define debug_printf if (__QTSSCALLBACKS_DEBUG__) qtss_printf


void*   QTSSCallbacks::QTSS_New(FourCharCode /*inMemoryIdentifier*/, UInt32 inSize)
{
    //
    // This callback is now deprecated because the server no longer uses FourCharCodes
    // for memory debugging. For clients that still use it, the default, non-debugging
    // version of New is used.
    
    //return OSMemory::New(inSize, inMemoryIdentifier, false);
    return OSMemory::New(inSize); 
}

void    QTSSCallbacks::QTSS_Delete(void* inMemory)
{
    OSMemory::Delete(inMemory);
}

void    QTSSCallbacks::QTSS_Milliseconds(SInt64* outMilliseconds)
{
    if (outMilliseconds != NULL)
        *outMilliseconds = OS::Milliseconds();
}

void    QTSSCallbacks::QTSS_ConvertToUnixTime(SInt64 *inQTSS_MilliSecondsPtr, time_t* outSecondsPtr)
{
    if ( (NULL != outSecondsPtr) && (NULL != inQTSS_MilliSecondsPtr) )
        *outSecondsPtr = OS::TimeMilli_To_UnixTimeSecs(*inQTSS_MilliSecondsPtr);
}



QTSS_Error  QTSSCallbacks::QTSS_AddRole(QTSS_Role inRole)
{
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    // Roles can only be added before modules have had their Initialize role invoked.
    if ((theState == NULL) ||  (theState->curRole != QTSS_Register_Role))
        return QTSS_OutOfState;
        
    return theState->curModule->AddRole(inRole);
}



QTSS_Error QTSSCallbacks::QTSS_LockObject(QTSS_Object inDictionary)
{
    if (inDictionary == NULL)
        return QTSS_BadArgument;
        
    ((QTSSDictionary*)inDictionary)->GetMutex()->Lock();
	((QTSSDictionary*)inDictionary)->SetLocked(true);
    return QTSS_NoErr;
}

QTSS_Error QTSSCallbacks::QTSS_UnlockObject(QTSS_Object inDictionary)
{
    if (inDictionary == NULL)
        return QTSS_BadArgument;
	
	((QTSSDictionary*)inDictionary)->SetLocked(false);    
    ((QTSSDictionary*)inDictionary)->GetMutex()->Unlock();
    
    return QTSS_NoErr;
}

QTSS_Error QTSSCallbacks::QTSS_CreateObjectType(QTSS_ObjectType* outType)
{
    QTSS_ObjectType type = QTSSDictionaryMap::CreateNewMap();
    if (type == 0)
        return QTSS_RequestFailed;
        
    *outType = type;
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_AddAttribute(QTSS_ObjectType inType, const char* inName, void* inUnused)
{
    //
    // This call is deprecated, make the new call with sensible default arguments
    return QTSSCallbacks::QTSS_AddStaticAttribute(inType, inName, inUnused, qtssAttrDataTypeUnknown);
}

QTSS_Error  QTSSCallbacks::QTSS_AddStaticAttribute(QTSS_ObjectType inObjectType, const char* inAttrName, void* inUnused, QTSS_AttrDataType inAttrDataType)
{
    Assert(inUnused == NULL);
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();

    // Static attributes can only be added before modules have had their Initialize role invoked.
    if ((theState == NULL) || (theState->curRole != QTSS_Register_Role))
        return QTSS_OutOfState;

    UInt32 theDictionaryIndex = QTSSDictionaryMap::GetMapIndex(inObjectType);
    if (theDictionaryIndex == QTSSDictionaryMap::kIllegalDictionary)
        return QTSS_BadArgument;
        
    QTSSDictionaryMap* theMap = QTSSDictionaryMap::GetMap(theDictionaryIndex);
    return theMap->AddAttribute(inAttrName, NULL, inAttrDataType, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe);
}

QTSS_Error  QTSSCallbacks::QTSS_AddInstanceAttribute(QTSS_Object inObject, const char* inAttrName, void* inUnused, QTSS_AttrDataType inAttrDataType)
{
    Assert(inUnused == NULL);
    if ((inObject == NULL) || (inAttrName == NULL))
        return QTSS_BadArgument;
    
    return ((QTSSDictionary*)inObject)->AddInstanceAttribute(inAttrName, NULL, inAttrDataType, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModeDelete | qtssAttrModePreempSafe);
}

QTSS_Error QTSSCallbacks::QTSS_RemoveInstanceAttribute(QTSS_Object inObject, QTSS_AttributeID inID)
{
    if (inObject == NULL  || (inID == qtssIllegalAttrID) )
        return QTSS_BadArgument;
    
    return ((QTSSDictionary*)inObject)->RemoveInstanceAttribute(inID);
}


QTSS_Error  QTSSCallbacks::QTSS_IDForAttr(QTSS_ObjectType inType, const char* inName, QTSS_AttributeID* outID)
{
    if (outID == NULL)
        return QTSS_BadArgument;
        
    UInt32 theDictionaryIndex = QTSSDictionaryMap::GetMapIndex(inType);
    if (theDictionaryIndex == QTSSDictionaryMap::kIllegalDictionary)
        return QTSS_BadArgument;
    
    return QTSSDictionaryMap::GetMap(theDictionaryIndex)->GetAttrID(inName, outID);
}

QTSS_Error QTSSCallbacks::QTSS_GetAttrInfoByIndex(QTSS_Object inObject, UInt32 inIndex, QTSS_Object* outAttrInfoObject)
{
    if (inObject == NULL)
        return QTSS_BadArgument;
    
    return ((QTSSDictionary*)inObject)->GetAttrInfoByIndex(inIndex, (QTSSAttrInfoDict**)outAttrInfoObject);
}

QTSS_Error QTSSCallbacks::QTSS_GetAttrInfoByID(QTSS_Object inObject, QTSS_AttributeID inAttrID, QTSS_Object* outAttrInfoObject)
{
    if (inObject == NULL  || (inAttrID == qtssIllegalAttrID) )
        return QTSS_BadArgument;
    
    return ((QTSSDictionary*)inObject)->GetAttrInfoByID(inAttrID, (QTSSAttrInfoDict**)outAttrInfoObject);
}

QTSS_Error QTSSCallbacks::QTSS_GetAttrInfoByName(QTSS_Object inObject, const char* inAttrName, QTSS_Object* outAttrInfoObject)
{
    if (inObject == NULL)
        return QTSS_BadArgument;
    
    return ((QTSSDictionary*)inObject)->GetAttrInfoByName(inAttrName, (QTSSAttrInfoDict**)outAttrInfoObject);
}


QTSS_Error  QTSSCallbacks::QTSS_GetValuePtr (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, void** outBuffer, UInt32* outLen)
{
    if ((inDictionary == NULL) || (outBuffer == NULL) || (outLen == NULL)  || (inID == qtssIllegalAttrID) )
        return QTSS_BadArgument;
    return ((QTSSDictionary*)inDictionary)->GetValuePtr(inID, inIndex, outBuffer, outLen);
}


QTSS_Error  QTSSCallbacks::QTSS_GetValue (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, void* ioBuffer, UInt32* ioLen)
{
    if (inDictionary == NULL  || (inID == qtssIllegalAttrID) )
        return QTSS_BadArgument;
    return ((QTSSDictionary*)inDictionary)->GetValue(inID, inIndex, ioBuffer, ioLen);
}

QTSS_Error  QTSSCallbacks::QTSS_GetValueAsString (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, char** outString)
{
    if (inDictionary == NULL)
        return QTSS_BadArgument;
    return ((QTSSDictionary*)inDictionary)->GetValueAsString(inID, inIndex, outString);
}

QTSS_Error  QTSSCallbacks::QTSS_TypeToTypeString(const QTSS_AttrDataType inType, char** outTypeString)
{
    if (outTypeString == NULL)
        return QTSS_BadArgument;
    
    *outTypeString = QTSSDataConverter::TypeToTypeString(inType);
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_TypeStringToType(char* inTypeString, QTSS_AttrDataType* outType)
{
    if ((inTypeString == NULL) || (outType == NULL))
        return QTSS_BadArgument;
        
    *outType = QTSSDataConverter::TypeStringToType(inTypeString);
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_StringToValue( char* inValueAsString, const QTSS_AttrDataType inType, void* ioBuffer, UInt32* ioBufSize)
{
    return  QTSSDataConverter::StringToValue(inValueAsString,inType,ioBuffer,ioBufSize);
}

QTSS_Error  QTSSCallbacks::QTSS_ValueToString( void* inValue, const UInt32 inValueLen, const QTSS_AttrDataType inType, char** outString)
{
    if ((inValue == NULL) || (outString == NULL))
        return QTSS_BadArgument;
        
     *outString = QTSSDataConverter::ValueToString(inValue,inValueLen,inType);
     return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_SetValue (QTSS_Object inDictionary, QTSS_AttributeID inID, UInt32 inIndex, const void* inBuffer,  UInt32 inLen)
{
    if ((inDictionary == NULL) || ((inBuffer == NULL) && (inLen > 0))  || (inID == qtssIllegalAttrID) )
        return QTSS_BadArgument;
    return ((QTSSDictionary*)inDictionary)->SetValue(inID, inIndex, inBuffer, inLen);
}

QTSS_Error  QTSSCallbacks::QTSS_SetValuePtr (QTSS_Object inDictionary, QTSS_AttributeID inID, const void* inBuffer,  UInt32 inLen)
{
    if ((inDictionary == NULL) || ((inBuffer == NULL) && (inLen > 0)))
        return QTSS_BadArgument;
    return ((QTSSDictionary*)inDictionary)->SetValuePtr(inID, inBuffer, inLen);
}

QTSS_Error  QTSSCallbacks::QTSS_CreateObject (QTSS_Object inDictionary, QTSS_AttributeID inID, QTSS_ObjectType inType, UInt32* outIndex, QTSS_Object* outCreatedObject)
{
    if ((inDictionary == NULL) || (outCreatedObject == NULL) || (outIndex == NULL)  || (inID == qtssIllegalAttrID) )
        return QTSS_BadArgument;
        
    QTSSDictionaryMap* theMap = NULL;
    if (inType != qtssDynamicObjectType)
    {
        UInt32 theDictionaryIndex = QTSSDictionaryMap::GetMapIndex(inType);
        if (theDictionaryIndex == QTSSDictionaryMap::kIllegalDictionary)
            return QTSS_BadArgument;
            
        theMap = QTSSDictionaryMap::GetMap(theDictionaryIndex);
    }
    
    return ((QTSSDictionary*)inDictionary)->CreateObjectValue(inID, outIndex, (QTSSDictionary**)outCreatedObject, theMap);
}

QTSS_Error  QTSSCallbacks::QTSS_GetNumValues (QTSS_Object inObject, QTSS_AttributeID inID, UInt32* outNumValues)
{
    if ((inObject == NULL) || (outNumValues == NULL) || (inID == qtssIllegalAttrID) )
        return QTSS_BadArgument;
        
    *outNumValues = ((QTSSDictionary*)inObject)->GetNumValues(inID);
    return QTSS_NoErr;
}

QTSS_Error QTSSCallbacks::QTSS_GetNumAttributes(QTSS_Object inObject,  UInt32* outNumValues)
{
        
    if (outNumValues == NULL)
        return QTSS_BadArgument;

    if (inObject == NULL)
        return QTSS_BadArgument;

    OSMutexLocker locker(((QTSSDictionary*)inObject)->GetMutex());

    QTSSDictionaryMap* theMap = NULL;
    *outNumValues = 0;

    // Get the Static Attribute count
    theMap = ((QTSSDictionary*)inObject)->GetDictionaryMap();
    if (theMap != NULL)
        *outNumValues += theMap->GetNumNonRemovedAttrs();
    // Get the Instance Attribute count
    theMap = ((QTSSDictionary*)inObject)->GetInstanceDictMap();
    if (theMap != NULL)
        *outNumValues += theMap->GetNumNonRemovedAttrs();

    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_RemoveValue (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex)
{
    if (inObject == NULL)
        return QTSS_BadArgument;
        
    return ((QTSSDictionary*)inObject)->RemoveValue(inID, inIndex);
}



QTSS_Error  QTSSCallbacks::QTSS_Write(QTSS_StreamRef inStream, void* inBuffer, UInt32 inLen, UInt32* outLenWritten, UInt32 inFlags)
{
    if (inStream == NULL)
        return QTSS_BadArgument;
    QTSS_Error theErr = ((QTSSStream*)inStream)->Write(inBuffer, inLen, outLenWritten, inFlags);
    
    // Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
    // level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
    // to replace them. So we have to replace them here.
    if (theErr == EAGAIN)
        return QTSS_WouldBlock;
    else if (theErr > 0)
        return QTSS_NotConnected;
    else
        return theErr;
}

QTSS_Error  QTSSCallbacks::QTSS_WriteV(QTSS_StreamRef inStream, iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength, UInt32* outLenWritten)
{
    if (inStream == NULL)
        return QTSS_BadArgument;
    QTSS_Error theErr = ((QTSSStream*)inStream)->WriteV(inVec, inNumVectors, inTotalLength, outLenWritten);

    // Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
    // level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
    // to replace them. So we have to replace them here.
    if (theErr == EAGAIN)
        return QTSS_WouldBlock;
    else if (theErr > 0)
        return QTSS_NotConnected;
    else
        return theErr;
}

QTSS_Error  QTSSCallbacks::QTSS_Flush(QTSS_StreamRef inStream)
{
    if (inStream == NULL)
        return QTSS_BadArgument;
    QTSS_Error theErr = ((QTSSStream*)inStream)->Flush();

    // Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
    // level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
    // to replace them. So we have to replace them here.
    if (theErr == EAGAIN)
        return QTSS_WouldBlock;
    else if (theErr > 0)
        return QTSS_NotConnected;
    else
        return theErr;
}

QTSS_Error  QTSSCallbacks::QTSS_Read(QTSS_StreamRef inStream, void* ioBuffer, UInt32 inBufLen, UInt32* outLengthRead)
{
    if ((inStream == NULL) || (ioBuffer == NULL))
        return QTSS_BadArgument;
    QTSS_Error theErr = ((QTSSStream*)inStream)->Read(ioBuffer, inBufLen, outLengthRead);

    // Server internally propogates POSIX errorcodes such as EAGAIN and ENOTCONN up to this
    // level. The API guarentees that no POSIX errors get returned, so we have QTSS_Errors
    // to replace them. So we have to replace them here.
    if (theErr == EAGAIN)
        return QTSS_WouldBlock;
    else if (theErr > 0)
        return QTSS_NotConnected;
    else
        return theErr;
}

QTSS_Error  QTSSCallbacks::QTSS_Seek(QTSS_StreamRef inStream, UInt64 inNewPosition)
{
    if (inStream == NULL)
        return QTSS_BadArgument;
    return ((QTSSStream*)inStream)->Seek(inNewPosition);
}


QTSS_Error  QTSSCallbacks::QTSS_Advise(QTSS_StreamRef inStream, UInt64 inPosition, UInt32 inAdviseSize)
{
    if (inStream == NULL)
        return QTSS_BadArgument;
    return ((QTSSStream*)inStream)->Advise(inPosition, inAdviseSize);
}



QTSS_Error  QTSSCallbacks::QTSS_OpenFileObject(char* inPath, QTSS_OpenFileFlags inFlags, QTSS_Object* outFileObject)
{
    if ((inPath == NULL) || (outFileObject == NULL))
        return QTSS_BadArgument;
    
    //
    // Create a new file object
    QTSSFile* theNewFile = NEW QTSSFile();
    QTSS_Error theErr = theNewFile->Open(inPath, inFlags);

    if (theErr != QTSS_NoErr)
        delete theNewFile; // No module wanted to open the file.
    else
        *outFileObject = theNewFile;
    
    return theErr;
}

QTSS_Error  QTSSCallbacks::QTSS_CloseFileObject(QTSS_Object inFileObject)
{
    if (inFileObject == NULL)
        return QTSS_BadArgument;
        
    QTSSFile* theFile = (QTSSFile*)inFileObject;

    theFile->Close();
    delete theFile;
    return QTSS_NoErr;
}


QTSS_Error  QTSSCallbacks::QTSS_CreateStreamFromSocket(int inFileDesc, QTSS_StreamRef* outStream)
{
    if (outStream == NULL)
        return QTSS_BadArgument;
    
    if (inFileDesc < 0)
        return QTSS_BadArgument;
        
    //
    // Create a new socket object
    *outStream = (QTSS_StreamRef)NEW QTSSSocket(inFileDesc);
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_DestroySocketStream(QTSS_StreamRef inStream)
{
    if (inStream == NULL)
        return QTSS_BadArgument;
    
    //
    // Note that the QTSSSocket destructor will call close on its file descriptor.
    // Calling module should not also close the file descriptor! (This is noted in the API)
    QTSSSocket* theSocket = (QTSSSocket*)inStream;
    delete theSocket;
    return QTSS_NoErr;
}


QTSS_Error  QTSSCallbacks::QTSS_AddService(const char* inServiceName, QTSS_ServiceFunctionPtr inFunctionPtr)
{
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();

    // This may happen if this callback is occurring on module-created thread
    if (theState == NULL)
        return QTSS_OutOfState;
        
    // Roles can only be added before modules have had their Initialize role invoked.
    if (theState->curRole != QTSS_Register_Role)
        return QTSS_OutOfState;

    return QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServiceDictIndex)->
                AddAttribute(inServiceName, (QTSS_AttrFunctionPtr)inFunctionPtr, qtssAttrDataTypeUnknown, qtssAttrModeRead);
}

QTSS_Error  QTSSCallbacks::QTSS_IDForService(const char* inTag, QTSS_ServiceID* outID)
{
    return QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServiceDictIndex)->
                GetAttrID(inTag, outID);
}

QTSS_Error  QTSSCallbacks::QTSS_DoService(QTSS_ServiceID inID, QTSS_ServiceFunctionArgsPtr inArgs)
{
    // Make sure that the service ID is in fact valid
    
    QTSSDictionaryMap* theMap = QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kServiceDictIndex);
    SInt32 theIndex = theMap->ConvertAttrIDToArrayIndex(inID);
    if (theIndex < 0)
        return QTSS_IllegalService;
    
    // Get the service function 
    QTSS_ServiceFunctionPtr theFunction = (QTSS_ServiceFunctionPtr)theMap->GetAttrFunction(theIndex);

    // Invoke it, return the result.    
    return (theFunction)(inArgs);
}


QTSS_Error QTSSCallbacks::QTSS_SendRTSPHeaders(QTSS_RTSPRequestObject inRef)
{
    if (inRef == NULL)
        return QTSS_BadArgument;
        
    ((RTSPRequestInterface*)inRef)->SendHeader();
    return QTSS_NoErr;
}

QTSS_Error QTSSCallbacks::QTSS_AppendRTSPHeader(QTSS_RTSPRequestObject inRef,
                                                        QTSS_RTSPHeader inHeader,
                                                        char* inValue,
                                                        UInt32 inValueLen)
{
    if ((inRef == NULL) || (inValue == NULL))
        return QTSS_BadArgument;
    if (inHeader >= qtssNumHeaders)
        return QTSS_BadArgument;
    
    StrPtrLen theValue(inValue, inValueLen);
    ((RTSPRequestInterface*)inRef)->AppendHeader(inHeader, &theValue);
    return QTSS_NoErr;
}

QTSS_Error QTSSCallbacks::QTSS_SendStandardRTSPResponse(QTSS_RTSPRequestObject inRTSPRequest,
                                                            QTSS_Object inRTPInfo,
                                                            UInt32 inFlags)
{
    if ((inRTSPRequest == NULL) || (inRTPInfo == NULL))
        return QTSS_BadArgument;
        
    switch (((RTSPRequestInterface*)inRTSPRequest)->GetMethod())
    {
        case qtssDescribeMethod:
            ((RTPSession*)inRTPInfo)->SendDescribeResponse((RTSPRequestInterface*)inRTSPRequest);
            return QTSS_NoErr;
        case qtssSetupMethod:
        {
            // Because QTSS_SendStandardRTSPResponse supports sending a proper 304 Not Modified on a SETUP,
            // but a caller typically won't be adding a stream for a 304 response, we have the policy of
            // making the caller pass in the QTSS_ClientSessionObject instead. That means we need to do
            // different things here depending...
            if (((RTSPRequestInterface*)inRTSPRequest)->GetStatus() == qtssRedirectNotModified)
                (void)((RTPSession*)inRTPInfo)->DoSessionSetupResponse((RTSPRequestInterface*)inRTSPRequest);
            else
            {
                if (inFlags & qtssSetupRespDontWriteSSRC)
                    ((RTPStream*)inRTPInfo)->DisableSSRC();
                else
                    ((RTPStream*)inRTPInfo)->EnableSSRC();
                
                ((RTPStream*)inRTPInfo)->SendSetupResponse((RTSPRequestInterface*)inRTSPRequest);
            }
            
            return QTSS_NoErr;
        }
        case qtssPlayMethod:
		case qtssRecordMethod:
            ((RTPSession*)inRTPInfo)->SendPlayResponse((RTSPRequestInterface*)inRTSPRequest, inFlags);
            return QTSS_NoErr;
        case qtssPauseMethod:
            ((RTPSession*)inRTPInfo)->SendPauseResponse((RTSPRequestInterface*)inRTSPRequest);
            return QTSS_NoErr;
        case qtssTeardownMethod:
            ((RTPSession*)inRTPInfo)->SendTeardownResponse((RTSPRequestInterface*)inRTSPRequest);
            return QTSS_NoErr;
        case qtssAnnounceMethod:
            ((RTPSession*)inRTPInfo)->SendAnnounceResponse((RTSPRequestInterface*)inRTSPRequest);
            return QTSS_NoErr;
    }
    return QTSS_BadArgument;
}




QTSS_Error  QTSSCallbacks::QTSS_AddRTPStream(QTSS_ClientSessionObject inClientSession, QTSS_RTSPRequestObject inRTSPRequest, QTSS_RTPStreamObject* outStream, QTSS_AddStreamFlags inFlags)
{
    if ((inClientSession == NULL) || (inRTSPRequest == NULL) ||(outStream == NULL))
        return QTSS_BadArgument;
    return ((RTPSession*)inClientSession)->AddStream((RTSPRequestInterface*)inRTSPRequest, (RTPStream**)outStream, inFlags);
}

QTSS_Error  QTSSCallbacks::QTSS_Play(QTSS_ClientSessionObject inClientSession, QTSS_RTSPRequestObject inRTSPRequest, QTSS_PlayFlags inPlayFlags)
{
    if (inClientSession == NULL)
        return QTSS_BadArgument;
    return ((RTPSession*)inClientSession)->Play((RTSPRequestInterface*)inRTSPRequest, inPlayFlags);
}

QTSS_Error  QTSSCallbacks::QTSS_Pause(QTSS_ClientSessionObject inClientSession)
{
    if (inClientSession == NULL)
        return QTSS_BadArgument;
    ((RTPSession*)inClientSession)->Pause();
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_Teardown(QTSS_ClientSessionObject inClientSession)
{
    if (inClientSession == NULL)
        return QTSS_BadArgument;
    
    ((RTPSession*)inClientSession)->Teardown();
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_RefreshTimeOut(QTSS_ClientSessionObject inClientSession)
{
    if (inClientSession == NULL)
        return QTSS_BadArgument;
    
    ((RTPSession*)inClientSession)->RefreshTimeouts();
    return QTSS_NoErr;
}



QTSS_Error  QTSSCallbacks::QTSS_RequestEvent(QTSS_StreamRef inStream, QTSS_EventType inEventMask)
{
    // First thing to do is to alter the thread's module state to reflect the fact
    // that an event is outstanding.
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    if (theState == NULL)
        return QTSS_RequestFailed;
        
    if (theState->curTask == NULL)
        return QTSS_OutOfState;
        
    theState->eventRequested = true;
    
    // Now, tell this stream to be ready for the requested event
    QTSSStream* theStream = (QTSSStream*)inStream;
    theStream->SetTask(theState->curTask);
    theStream->RequestEvent(inEventMask);
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_SignalStream(QTSS_StreamRef inStream)
{
    if (inStream == NULL)
        return QTSS_BadArgument;
    
    QTSSStream* theStream = (QTSSStream*)inStream;
    if (theStream->GetTask() != NULL)
        theStream->GetTask()->Signal(Task::kReadEvent);
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_SetIdleTimer(SInt64 inMsecToWait)
{
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    // This may happen if this callback is occurring on module-created thread
    if (theState == NULL)
        return QTSS_RequestFailed;
        
    if (theState->curTask == NULL)
        return QTSS_OutOfState;
        
    theState->eventRequested = true;
    theState->idleTime = inMsecToWait;
    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_SetIdleRoleTimer(SInt64 inMsecToWait)
{

    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
    
    // This may happen if this callback is occurring on module-created thread
    if (theState == NULL)
        return QTSS_RequestFailed;
        
    if (theState->curModule == NULL)
        return QTSS_RequestFailed;


    QTSSModule* theModule = theState->curModule;
    QTSS_ModuleState* thePrivateModuleState = theModule->GetModuleState();
    thePrivateModuleState->idleTime = inMsecToWait;
    theModule->Signal(Task::kUpdateEvent); 


    return QTSS_NoErr;
}

QTSS_Error  QTSSCallbacks::QTSS_RequestLockedCallback()
{
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    // This may happen if this callback is occurring on module-created thread
    if (theState == NULL)
        return QTSS_RequestFailed;
        
    if (theState->curTask == NULL)
        return QTSS_OutOfState;
        
    theState->globalLockRequested = true; //x

    return QTSS_NoErr;
}

Bool16      QTSSCallbacks::QTSS_IsGlobalLocked()
{
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    // This may happen if this callback is occurring on module-created thread
    if (theState == NULL)
        return false;
        
    if (theState->curTask == NULL)
        return false;

    return theState->isGlobalLocked;
}

QTSS_Error  QTSSCallbacks::QTSS_UnlockGlobalLock()
{
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    // This may happen if this callback is occurring on module-created thread
    if (theState == NULL)
        return QTSS_RequestFailed;
        
    if (theState->curTask == NULL)
        return QTSS_OutOfState;
        
    ((Task *)OSThread::GetCurrent())->GlobalUnlock();
    
    theState->globalLockRequested = false; 
    theState->isGlobalLocked = false; 


    return QTSS_NoErr;
}


QTSS_Error  QTSSCallbacks::QTSS_Authenticate(const char* inAuthUserName, const char* inAuthResourceLocalPath, const char* inAuthMoviesDir, QTSS_ActionFlags inAuthRequestAction, QTSS_AuthScheme inAuthScheme, QTSS_RTSPRequestObject ioAuthRequestObject)
{
    if((inAuthUserName == NULL) || (inAuthResourceLocalPath == NULL) || (inAuthMoviesDir == NULL) || (ioAuthRequestObject == NULL)) 
        return QTSS_BadArgument;
    if(inAuthRequestAction == qtssActionFlagsNoFlags)
        return QTSS_BadArgument;
    if(inAuthScheme == qtssAuthNone)
        return QTSS_BadArgument;

    // First create a RTSPRequestInterface object 
    // There is no session attached to it, so just pass in NULL for the RTSPSession
    RTSPRequestInterface *request =  (RTSPRequestInterface *) ioAuthRequestObject;
    // Set all the attributes required by the authentication module, using the input values
    (void) request->SetValue(qtssRTSPReqUserName, 0,  inAuthUserName , ::strlen(inAuthUserName), QTSSDictionary::kDontObeyReadOnly);
    (void) request->SetValue(qtssRTSPReqLocalPath, 0,  inAuthResourceLocalPath , ::strlen(inAuthResourceLocalPath), QTSSDictionary::kDontObeyReadOnly);
    (void) request->SetValue(qtssRTSPReqRootDir, 0,  inAuthMoviesDir , ::strlen(inAuthMoviesDir), QTSSDictionary::kNoFlags);
    (void) request->SetValue(qtssRTSPReqAction, 0,  (const void *)&inAuthRequestAction , sizeof(QTSS_ActionFlags), QTSSDictionary::kNoFlags);
    (void) request->SetValue(qtssRTSPReqAuthScheme, 0,  (const void *)&inAuthScheme , sizeof(QTSS_AuthScheme), QTSSDictionary::kDontObeyReadOnly);
    QTSSUserProfile *profile = request->GetUserProfile();
    (void) profile->SetValue(qtssUserName, 0, inAuthUserName, ::strlen(inAuthUserName), QTSSDictionary::kDontObeyReadOnly);
    
    
    // Because this is a role being executed from inside a callback, we need to
    // make sure that QTSS_RequestEvent will not work.
    Task* curTask = NULL;
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    if (theState != NULL)
        curTask = theState->curTask;
    
    // Setup the authentication param block
    QTSS_RoleParams theAuthenticationParams;
    theAuthenticationParams.rtspAthnParams.inRTSPRequest = request;
            
    QTSS_Error theErr = QTSS_RequestFailed;
    
    UInt32 x = 0;
    UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPAthnRole);
    QTSSModule* theModulePtr = NULL;
    Bool16 allowedDefault = QTSServerInterface::GetServer()->GetPrefs()->GetAllowGuestDefault();
    Bool16 allowed = allowedDefault; //server pref?
    Bool16 hasUser = false; 
    Bool16 handled = false;
    
    
    // Call all the modules that are registered for the RTSP Authorize Role 
    for ( ; x < numModules; x++)
    {
        request->SetAllowed(allowedDefault);  
        request->SetHasUser(false);
        request->SetAuthHandled(false);
    
        debug_printf(" QTSSCallbacks::QTSS_Authenticate calling module module = %lu numModules=%lu\n", x,numModules);
        theModulePtr = QTSServerInterface::GetModule(QTSSModule::kRTSPAthnRole, x);
        theErr =  QTSS_NoErr;
        if (theModulePtr)
        {    
            theErr = theModulePtr->CallDispatch(QTSS_RTSPAuthenticate_Role, &theAuthenticationParams);
            debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu ModuleError=%ld\n", x,numModules, theErr);
        }
        else
        {   
            debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu is NULL! numModules=%lu\n", x,numModules);
            continue;
        }
        allowed = request->GetAllowed();
        hasUser = request->GetHasUser();
        handled = request->GetAuthHandled();
        debug_printf("QTSSCallbacks::QTSS_Authenticate allowedDefault =%d allowed= %d hasUser = %d handled=%d \n",allowedDefault, allowed,hasUser, handled);
      
                  
        if (hasUser || handled ) //See RTSPSession.cpp::Run state=kAuthenticatingRequest
        {   
            debug_printf(" QTSSCallbacks::QTSS_Authenticate skipping other modules fCurrentModule = %lu numModules=%lu\n", x,numModules);
            break;
        }
    }

    
    // Reset the curTask to what it was before this role started
    if (theState != NULL)
        theState->curTask = curTask;

    return theErr;
}

QTSS_Error	QTSSCallbacks::QTSS_Authorize(QTSS_RTSPRequestObject inAuthRequestObject, char** outAuthRealm, Bool16* outAuthUserAllowed)
{
    RTSPRequestInterface* request = (RTSPRequestInterface *) inAuthRequestObject;
    if (request == NULL)
        return QTSS_BadArgument;
            
    // Because this is a role being executed from inside a callback, we need to
    // make sure that QTSS_RequestEvent will not work.
    Task* curTask = NULL;
    QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
    if (OSThread::GetCurrent() != NULL)
        theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();
        
    if (theState != NULL)
        curTask = theState->curTask;
        
    QTSS_RoleParams theParams;
    theParams.rtspRequestParams.inRTSPSession = NULL;
    theParams.rtspRequestParams.inRTSPRequest = request;
    theParams.rtspRequestParams.inClientSession = NULL;

    QTSS_Error theErr = QTSS_RequestFailed;
    UInt32 x = 0;
    UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPAuthRole);
    QTSSModule* theModulePtr = NULL;
    Bool16 		allowedDefault =  QTSServerInterface::GetServer()->GetPrefs()->GetAllowGuestDefault();
    *outAuthUserAllowed = allowedDefault;
    Bool16      allowed = allowedDefault; //server pref?
    Bool16      hasUser = false; 
    Bool16      handled = false;
    
    
    // Call all the modules that are registered for the RTSP Authorize Role 
    
    for ( ; x < numModules; x++)
    {
        request->SetAllowed(true);  
        request->SetHasUser(false);
        request->SetAuthHandled(false);
    
        debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu\n", x,numModules);
        theModulePtr = QTSServerInterface::GetModule(QTSSModule::kRTSPAuthRole, x);
        theErr =  QTSS_NoErr;
        if (theModulePtr)
        {       
            if (__QTSSCALLBACKS_DEBUG__)
                theModulePtr->GetValue(qtssModName)->PrintStr("QTSSModule::CallDispatch ENTER module=", "\n");
           
            theErr = theModulePtr->CallDispatch(QTSS_RTSPAuthorize_Role, &theParams);
            debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu ModuleError=%ld\n", x,numModules, theErr);
        }
        else
        {    debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu is NULL! numModules=%lu\n", x,numModules);
             continue;
        }

        allowed = request->GetAllowed();
        hasUser = request->GetHasUser();
        handled = request->GetAuthHandled();
        debug_printf("QTSSCallbacks::QTSS_Authorize allowedDefault =%d allowed= %d hasUser = %d handled=%d \n",allowedDefault, allowed,hasUser, handled);
    
        *outAuthUserAllowed = allowed;    
        //notes:
        //if (allowed && !handled)  break; //old module               
        //if (!allowed && handled) /new module handled the request but not authorized keep trying
        //if (allowed && handled) //new module allowed but keep trying in case someone denies.
            
        if (!allowed && !handled)  //old module break on !allowed
        {   
            debug_printf("RTSPSession.cpp::Run(kAuthorizingRequest)  skipping other modules fCurrentModule = %lu numModules=%lu\n", x,numModules);
            break;
        }
    }
    
    // outAuthRealm is set to the realm that is given by the module that has denied authentication
    StrPtrLen* realm = request->GetValue(qtssRTSPReqURLRealm);
    *outAuthRealm = realm->GetAsCString();
    
    return theErr;
}

void QTSSCallbacks::QTSS_LockStdLib()
{
    OS::GetStdLibMutex()->Lock();
}

void QTSSCallbacks::QTSS_UnlockStdLib()
{
    OS::GetStdLibMutex()->Unlock();
}

