⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rvh323timer.c

📁 基于h323协议的软phone
💻 C
📖 第 1 页 / 共 2 页
字号:
/***********************************************************************
        Copyright (c) 2002 RADVISION Ltd.
************************************************************************
NOTICE:
This document contains information that is confidential and proprietary
to RADVISION Ltd.. No part of this document may be reproduced in any
form whatsoever without written prior approval by RADVISION Ltd..

RADVISION Ltd. reserve the right to revise this publication and make
changes without obligation to notify any person of such revisions or
changes.
***********************************************************************/

#include "rv64ascii.h"
#include "rvtimer.h"
#include "rvtimestamp.h"
#include "rvlog.h"

#include "ra.h"
#include "rvthreadinstance.h"
#include "rvh323timer.h"

#ifdef __cplusplus
extern "C" {
#endif


/* Number of timers per page to allocate */
#define RV_H323TIMERS_PER_PAGE (100)


static RvUint32 RvH323TimersInitialized = 0;

/* Log source object */
static RvLogSource RvH323TimersLog;

/* Thread local storage index used for the timers */
static RvUint32 RvH323TimersIndex = RV_UINT32_MAX;



typedef struct
{
    RvTimerQueue*   timerQ; /* Timers queue we're working with for these timers */
    HRA             array; /* Array of actual timer objects */
    RvThread*       threadInfo; /* Thread this timers are processed in */
#if (RV_OS_TYPE == RV_OS_TYPE_WIN32)
    HWND            hWnd;
#endif
} RvH323Timers;



/* Delete the current thread's timer queue */
static RvStatus ThreadDeleteTimersQueue(
    IN  const RvChar*   objectName,
    IN  void*           context,
    IN  void*           objectPtr)
{
    RvTimerQueue* timerQ = (RvTimerQueue *)objectPtr;

    RV_UNUSED_ARG(objectName);
    RV_UNUSED_ARG(context);

    RvTimerQueueDestruct(timerQ);
    return RvMemoryFree(timerQ);
}


/* Create the timers queue on the current thread */
static RvStatus ThreadCreateTimersQueue(
    IN    const RvChar*             objectName,
    IN    void*                     context,
    IN    RvSize_t                  amountNeeded,
    INOUT void**                    objectPtr,
    OUT   RvSize_t*                 amountAllocated,
    OUT   ThreadInstanceDeleteFunc* deleteFunc)
{
    RvTimerQueue* timerQ;
    RvStatus status;

    RV_UNUSED_ARG(objectName);
    RV_UNUSED_ARG(context);

    if ((*objectPtr) != NULL)
    {
        /* We're adding more timers */
        timerQ = (RvTimerQueue *)(*objectPtr);

        *amountAllocated = RvTimerQueueAddSize(timerQ, amountNeeded);
    }
    else
    {
        /* New allocation of a timer queue */
        status = RvMemoryAlloc(NULL, (void**)&timerQ, sizeof(RvTimerQueue));
        if (status != RV_OK)
            return status;

        status = RvTimerQueueConstruct(timerQ, RV_TIMER_QTYPE_FIXED, amountNeeded, 0, 0, 0,
            RV_H323TIMERS_PER_PAGE, NULL);
        if (status != RV_OK)
            return status;

        *objectPtr = timerQ;
        *amountAllocated = RvTimerQueueGetSize(timerQ);
        *deleteFunc = ThreadDeleteTimersQueue;
    }

    return RV_OK;
}



#if (RV_OS_TYPE == RV_OS_TYPE_WIN32)
/* For windows, we want to handle applications that will not use our seliSelect() loop.
   To do that, we must be nice and set the timers through a specific window and not through
   the IO layer. */

#define RV_H323TIMER_REFRESH    WM_USER+100 /* Event used to update the timer of the window */

#define RV_H323TIMER_PRECISION  11 /* Precision bits to use. The lower the values - the better the precision.
                                      Setting this value to lower than 10 is not desirable and might cause
                                      degradation in performance. */


static RvUint32 RvH323TimersHWNDIndex = RV_UINT32_MAX;


#ifdef GetWindowLongPtr
#define GetNextTimeout(hWnd) (RvInt64*)GetWindowLongPtr(hWnd, GWLP_USERDATA)
#else
#define GetNextTimeout(hWnd) (RvInt64*)GetWindowLong(hWnd, GWL_USERDATA)
#endif



/************************************************************************
 * h323TimerResetTimeout
 * purpose : Reset the timers window according to the next timer to pop
 * input   : timers     - Timers queue to reset. NULL if current
 * output  : none
 * return  : none
 ************************************************************************/
static void h323TimerResetTimeout(
    IN RvH323Timers *timers)
{
    RvInt64*        nextTimeout;
    RvInt64         remainingTime;
    UINT            remainingTimeInMs;
    RvStatus        status;
    RvTimerQueue*   timerQ;
    HWND            hWnd = NULL;

    /* Get timer handles first */
    if (timers == NULL)
    {
        status = ThreadInstanceGetObject(RvH323TimersIndex, (void**)&timerQ);
        if (status == RV_OK)
            status = ThreadInstanceGetObject(RvH323TimersHWNDIndex, (void**)&hWnd);
        if (status != RV_OK)
            return;
    }
    else
    {
        timerQ = timers->timerQ;
        hWnd = timers->hWnd;
    }

    /* Find out the remaining time we have */
    status = RvTimerQueueNextEvent(timerQ, &remainingTime);
    if (status != RV_OK)
        return;

    /* Calculate the absolute time of the next timer */
    if (remainingTime > 0)
    {
        remainingTimeInMs = (UINT)Rv64Divide(remainingTime, RV_TIME64_NSECPERMSEC);
        remainingTime = (remainingTime + RvTimestampGet()) >> RV_H323TIMER_PRECISION;
    }
    else
    {
        remainingTime = 0;
        remainingTimeInMs = 1;
    }

    nextTimeout = GetNextTimeout(hWnd);

    /* See if the next timeout is far enough. We're not trying to get something better than
       milliseconds in our calculations here */
    if (*nextTimeout > remainingTime)
    {
        /* We should update the timer we're holding on this window */
        /* Kill the current timer on window */
        if ((timers == NULL) || (timers->threadInfo == RvThreadCurrent()))
        {
            if (remainingTimeInMs == 0)
                remainingTimeInMs = 1;

            /* Set the next timer in window */
            if (SetTimer(hWnd, 1, remainingTimeInMs, NULL) == 0)
            {
                RvLogExcep(&RvH323TimersLog, (&RvH323TimersLog,
                    "h323TimerResetTimeout: Failed to set timer (error=%d)",
                    GetLastError()));
            }

            *nextTimeout = remainingTime;
        }
        else
        {
            PostMessage(hWnd, RV_H323TIMER_REFRESH, (WPARAM)0, (LPARAM)0);
        }
    }
}



LRESULT RVCALLCONV
h323TimerWinFunc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        case WM_CLOSE:
        {
            /* Closing the window - just kill the damn timer and the window */
            RvMemoryFree(GetNextTimeout(hWnd));
            KillTimer(hWnd, 1);
            DestroyWindow(hWnd);
            break;
        }

        case WM_TIMER:
        {
            /* Timer expiration - we should check our global timers queue */
            if (RvH323TimersInitialized > 0)
            {
                RvTimerQueue* timerQ;
                RvStatus status;

                status = ThreadInstanceGetObject(RvH323TimersIndex, (void**)&timerQ);
                if (status == RV_OK)
                {
                    RvTimerQueueService(timerQ, 0, NULL);

                    /* Make sure to refresh the timer... */
                    KillTimer(hWnd, 1);
                    *GetNextTimeout(hWnd) = RV_INT64_MAX; /* We have no timeout now... */
                    h323TimerResetTimeout(NULL);
                }
            }
            break;
        }

        case RV_H323TIMER_REFRESH:
        {
            h323TimerResetTimeout(NULL);
            break;
        }

        default:
            return DefWindowProc(hWnd,uMsg,wParam,lParam);
    }

    return 0l;
}


/* Delete the current thread's timers HWND */
static RvStatus DeleteTimersHWND(
    IN  const RvChar*   objectName,
    IN  void*           context,
    IN  void*           objectPtr)
{
    HWND hWnd = (HWND)objectPtr;

    RV_UNUSED_ARG(objectName);
    RV_UNUSED_ARG(context);

    /* Kill the associated window if there is one */
    if (IsWindow(hWnd))
    {
        SendMessage(hWnd, WM_CLOSE, (WPARAM)0, (LPARAM)0);
    }

    return RV_OK;
}


/* Create the timers HWND on the current thread */
static RvStatus CreateTimersHWND(
    IN    const RvChar*             objectName,
    IN    void*                     context,
    IN    RvSize_t                  amountNeeded,
    INOUT void**                    objectPtr,
    OUT   RvSize_t*                 amountAllocated,
    OUT   ThreadInstanceDeleteFunc* deleteFunc)
{
    RvInt64* nextTimeout;
    RvStatus status;
    WNDCLASS wc;
    HWND hWnd;

    RV_UNUSED_ARG(objectName);
    RV_UNUSED_ARG(context);
    RV_UNUSED_ARG(amountNeeded);

    status = RvMemoryAlloc(NULL, (void**)&nextTimeout, sizeof(RvInt64)) ;
    if (status != RV_OK)
        return status;
    *nextTimeout = RV_INT64_MAX;

    memset (&wc, 0, sizeof (WNDCLASS));

    wc.lpfnWndProc    = h323TimerWinFunc;
    wc.hInstance      = NULL;
    wc.lpszClassName  = "h323TiWin";

    RegisterClass(&wc);
    hWnd = CreateWindow("h323TiWin", NULL,WS_OVERLAPPED | WS_MINIMIZE,
        0, 0, 0, 0, NULL, NULL, NULL, NULL);

    if (IsWindow(hWnd))
    {
        *objectPtr = hWnd;
        *amountAllocated = 0;
        *deleteFunc = DeleteTimersHWND;
#ifdef SetWindowLongPtr
        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)nextTimeout);
#else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -