progdown.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:21k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: RCSL 1.0/RPSL 1.0
  3.  *
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
  5.  *
  6.  * The contents of this file, and the files included with this file, are
  7.  * subject to the current version of the RealNetworks Public Source License
  8.  * Version 1.0 (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the RealNetworks Community Source License Version 1.0
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
  12.  * in which case the RCSL will apply. You may also obtain the license terms
  13.  * directly from RealNetworks.  You may not use this file except in
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or
  16.  * RCSL for the rights, obligations and limitations governing use of the
  17.  * contents of the file.
  18.  *
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the
  20.  * developer of the Original Code and owns the copyrights in the portions
  21.  * it created.
  22.  *
  23.  * This file, and the files included with this file, is distributed and made
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  28.  *
  29.  * Technology Compatibility Kit Test Suite(s) Location:
  30.  *    http://www.helixcommunity.org/content/tck
  31.  *
  32.  * Contributor(s):
  33.  *
  34.  * ***** END LICENSE BLOCK ***** */
  35. #include "hxtypes.h"
  36. #include "hxcom.h"
  37. #include "ihxpckts.h"
  38. #include "hlxclib/sys/stat.h"
  39. #include "hxdataf.h"
  40. #include "hxprefs.h"
  41. #include "hxmon.h"
  42. #include "hxcomm.h"
  43. #include "hxcbobj.h"
  44. #include "hxprefutil.h"
  45. #include "pckunpck.h"
  46. #include "baseobj.h"
  47. #include "hxtick.h"
  48. #include "smplmlog.h"
  49. #include "progdown.h"
  50. CProgressiveDownloadMonitor::CProgressiveDownloadMonitor()
  51. {
  52.     MLOG_PD(NULL, "CON CProgressiveDownloadMonitor 0x%08xn", this);
  53.     m_pContext               = NULL;
  54.     m_pDataFile              = NULL;
  55.     m_pResponse              = NULL;
  56.     m_pScheduler             = NULL;
  57.     m_pRegistry              = NULL;
  58.     m_pStatCallback          = NULL;
  59.     m_pProgCallback          = NULL;
  60.     m_ulStatCallbackInterval = PROGDOWN_STAT_INTERVAL_DEFAULT;
  61.     m_ulCurStatInterval      = PROGDOWN_STAT_INTERVAL_INITIAL;
  62.     m_ulProgCallbackInterval = PROGDOWN_FAIL_INTERVAL_DEFAULT;
  63.     m_ulFinishedTime         = PROGDOWN_FINISHED_TIME_DEFAULT;
  64.     m_ulLastFileSize         = 0;
  65.     m_ulTickAtLastFileSize   = 0;
  66.     m_ulURLRegistryID        = 0;
  67.     m_ulIsProgRegistryID     = 0;
  68.     m_ulFormerProgRetryCount = 0;
  69.     m_ulFormerProgRetryInit  = PROGDOWN_FORMER_PROG_RETRY_INIT;
  70.     m_ulNotProgRetryCount    = 0;
  71.     m_ulNotProgRetryInit     = PROGDOWN_NOT_PROG_RETRY_INIT;
  72.     m_bIsProgressive         = FALSE;
  73.     m_bMonitorEnabled        = TRUE;
  74.     m_bHasBeenProgressive    = FALSE;
  75. }
  76. CProgressiveDownloadMonitor::~CProgressiveDownloadMonitor()
  77. {
  78.     MLOG_PD(NULL, "DES CProgressiveDownloadMonitor 0x%08xn", this);
  79.     Close();
  80. }
  81. HX_RESULT CProgressiveDownloadMonitor::Init(IUnknown* pContext, IHXDataFile* pFile,
  82.                                             CProgressiveDownloadMonitorResponse* pResponse)
  83. {
  84.     MLOG_PD(NULL, "CProgressiveDownloadMonitor::Init() this=0x%08xn", this);
  85.     HX_RESULT retVal = HXR_FAIL;
  86.     if (pContext && pFile && pResponse)
  87.     {
  88.         // Clear out any current state
  89.         Close();
  90.         // Save the context
  91.         m_pContext = pContext;
  92.         m_pContext->AddRef();
  93.         // Save the file
  94.         m_pDataFile = pFile;
  95.         // XXXMEH - We will not AddRef the IHXDataFile for now, because
  96.         // some users of the IHXFileObject do not call IHXFileObject::Close()
  97.         // before releasing the file object. If that is the case, then 
  98.         // the IHXDataFile never destructs. If we ever exhaustively go through
  99.         // and verify that all users of smplfsys correctly call ::Close(),
  100.         // then we can remove the commented-out AddRef().
  101. //        m_pDataFile->AddRef();
  102.         // Save the response pointer
  103.         m_pResponse = pResponse;
  104.         m_pResponse->AddRef();
  105.         // Get the schedule interface
  106.         retVal = m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  107.         if (SUCCEEDED(retVal))
  108.         {
  109.             // Get the IHXRegistry interface
  110.             m_pContext->QueryInterface(IID_IHXRegistry, (void**) &m_pRegistry);
  111.             // Check preferences to see if alternate values
  112.             // for stat callback interval, fail callback interval
  113.             // and finished duration are specified
  114.             CheckPreferenceValues(m_bMonitorEnabled,
  115.                                   m_ulStatCallbackInterval,
  116.                                   m_ulProgCallbackInterval,
  117.                                   m_ulFinishedTime,
  118.                                   m_ulFormerProgRetryInit,
  119.                                   m_ulNotProgRetryInit);
  120.             // Initialize the progressive state variables
  121.             m_ulLastFileSize       = GetFileSizeNow();
  122.             m_ulTickAtLastFileSize = HX_GET_BETTERTICKCOUNT();
  123.             // Initialize the number of times to retry
  124.             // if the file has not been progressive
  125.             m_ulNotProgRetryCount = m_ulNotProgRetryInit;
  126.             // Init the registry stats
  127.             InitRegistryStats();
  128.         }
  129.     }
  130.     return retVal;
  131. }
  132. HX_RESULT CProgressiveDownloadMonitor::Close()
  133. {
  134.     MLOG_PD(NULL, "CProgressiveDownloadMonitor::Close() this=0x%08xn", this);
  135.     HX_RESULT retVal = HXR_OK;
  136.     // Clear any stat callback
  137.     if (m_pStatCallback) m_pStatCallback->Cancel(m_pScheduler);
  138.     HX_RELEASE(m_pStatCallback);
  139.     // Clear any fail callback
  140.     CancelCallback();
  141.     HX_RELEASE(m_pProgCallback);
  142.     // Release member variables
  143.     HX_RELEASE(m_pContext);
  144.         // XXXMEH - We will not AddRef the IHXDataFile for now, because
  145.         // some users of the IHXFileObject do not call IHXFileObject::Close()
  146.         // before releasing the file object. If that is the case, then 
  147.         // the IHXDataFile never destructs. If we ever exhaustively go through
  148.         // and verify that all users of smplfsys correctly call ::Close(),
  149.         // then we can remove the commented-out HX_RELEASE()
  150. //    HX_RELEASE(m_pDataFile);
  151.     m_pDataFile = NULL;
  152.     HX_RELEASE(m_pResponse);
  153.     HX_RELEASE(m_pScheduler);
  154.     HX_RELEASE(m_pRegistry);
  155.     // Reset state variables to defaults
  156.     m_ulStatCallbackInterval = PROGDOWN_STAT_INTERVAL_DEFAULT;
  157.     m_ulCurStatInterval      = PROGDOWN_STAT_INTERVAL_INITIAL;
  158.     m_ulProgCallbackInterval = PROGDOWN_FAIL_INTERVAL_DEFAULT;
  159.     m_ulFinishedTime         = PROGDOWN_FINISHED_TIME_DEFAULT;
  160.     m_ulLastFileSize         = 0;
  161.     m_ulTickAtLastFileSize   = 0;
  162.     m_ulURLRegistryID        = 0;
  163.     m_ulIsProgRegistryID     = 0;
  164.     m_ulFormerProgRetryCount = 0;
  165.     m_ulFormerProgRetryInit  = PROGDOWN_FORMER_PROG_RETRY_INIT;
  166.     m_ulNotProgRetryCount    = 0;
  167.     m_ulNotProgRetryInit     = PROGDOWN_NOT_PROG_RETRY_INIT;
  168.     m_bIsProgressive         = FALSE;
  169.     m_bMonitorEnabled        = TRUE;
  170.     m_bHasBeenProgressive    = FALSE;
  171.     return retVal;
  172. }
  173. HX_RESULT CProgressiveDownloadMonitor::ScheduleCallback()
  174. {
  175.     MLOG_PD(NULL, "CProgressiveDownloadMonitor::ScheduleCallback() this=0x%08x tick=%lun",
  176.             this, HX_GET_BETTERTICKCOUNT());
  177.     HX_RESULT retVal = HXR_FAIL;
  178.     if (m_pScheduler)
  179.     {
  180.         if (!m_pProgCallback)
  181.         {
  182.             m_pProgCallback = new CHXGenericCallback(this, CProgressiveDownloadMonitor::ProgCallback);
  183.             if (m_pProgCallback)
  184.             {
  185.                 m_pProgCallback->AddRef();
  186.             }
  187.         }
  188.         if (m_pProgCallback)
  189.         {
  190.             // Clear the return value
  191.             retVal = HXR_OK;
  192.             // Do we already have a callback pending?
  193.             if (!m_pProgCallback->IsCallbackPending())
  194.             {
  195.                 // No callback pending, schedule one
  196.                 m_pProgCallback->ScheduleRelative(m_pScheduler, m_ulProgCallbackInterval);
  197.             }
  198.         }
  199.     }
  200.     return retVal;
  201. }
  202. BOOL CProgressiveDownloadMonitor::IsCallbackPending()
  203. {
  204.     BOOL bRet = FALSE;
  205.     if (m_pProgCallback)
  206.     {
  207.         bRet = m_pProgCallback->IsCallbackPending();
  208.     }
  209.     return bRet;
  210. }
  211. void CProgressiveDownloadMonitor::CancelCallback()
  212. {
  213.     if (m_pProgCallback && m_pProgCallback->IsCallbackPending())
  214.     {
  215.         m_pProgCallback->Cancel(m_pScheduler);
  216.     }
  217. }
  218. HX_RESULT CProgressiveDownloadMonitor::BeginSizeMonitoring()
  219. {
  220.     HX_RESULT retVal = HXR_FAIL;
  221.     // Create the stat callback if it doesn't
  222.     // already exist
  223.     if (!m_pStatCallback)
  224.     {
  225.         m_pStatCallback = new CHXGenericCallback(this, CProgressiveDownloadMonitor::StatCallback);
  226.         if (m_pStatCallback)
  227.         {
  228.             m_pStatCallback->AddRef();
  229.         }
  230.     }
  231.     if (m_pStatCallback)
  232.     {
  233.         // Clear the return value
  234.         retVal = HXR_OK;
  235.         // Do we already have a callback scheduled? If so,
  236.         // then we have already begun size monitoring.
  237.         if (!m_pStatCallback->IsCallbackPending())
  238.         {
  239.             // Initialize the progressive state variables
  240.             m_ulLastFileSize       = GetFileSizeNow();
  241.             m_ulTickAtLastFileSize = HX_GET_BETTERTICKCOUNT();
  242.             m_ulCurStatInterval    = PROGDOWN_STAT_INTERVAL_INITIAL;
  243.             // Kick off the callbacks, if monitoring is enabled
  244.             ScheduleStatCallback();
  245.         }
  246.     }
  247.     return retVal;
  248. }
  249. void CProgressiveDownloadMonitor::EndSizeMonitoring()
  250. {
  251.     // If there was a size monitoring callback
  252.     // scheduled, then cancel it
  253.     if (m_pStatCallback)
  254.     {
  255.         m_pStatCallback->Cancel(m_pScheduler);
  256.     }
  257. }
  258. UINT32 CProgressiveDownloadMonitor::GetFileSizeNow()
  259. {
  260.     UINT32 ulRet = 0;
  261.     if (m_pDataFile)
  262.     {
  263.         // Stat the file
  264.         struct stat sStat;
  265.         if (SUCCEEDED(m_pDataFile->Stat(&sStat)))
  266.         {
  267.             // Set the return value
  268.             ulRet = (UINT32) sStat.st_size;
  269.         }
  270.     }
  271.     return ulRet;
  272. }
  273. void CProgressiveDownloadMonitor::MonitorFileSize()
  274. {
  275.     MLOG_PD(NULL, "CProgressiveDownloadMonitor::MonitorFileSize() this=0x%08x tick=%lun",
  276.             this, HX_GET_BETTERTICKCOUNT());
  277.     // Save the current m_bIsProgressive value
  278.     BOOL bTmp = m_bIsProgressive;
  279.     // Get the file size and tick count
  280.     UINT32 ulFileSize = GetFileSizeNow();
  281.     UINT32 ulTick     = HX_GET_BETTERTICKCOUNT();
  282.     // Is the file size the same as m_ulLastFileSize?
  283.     if (ulFileSize != m_ulLastFileSize)
  284.     {
  285.         MLOG_PD(NULL, "tNewFileSize=%lun", ulFileSize);
  286.         // The filesize has changed, so we know
  287.         // this file is progressive
  288.         m_bIsProgressive = TRUE;
  289.         // Reset the former progressive retry count to
  290.         // its initial value
  291.         m_ulFormerProgRetryCount = m_ulFormerProgRetryInit;
  292.         // Reset the not progressive retry count to
  293.         // its initial value
  294.         m_ulNotProgRetryCount = m_ulNotProgRetryInit;
  295.         // If the file size is different even once,
  296.         // then this file has a history of being progressive.
  297.         // We keep this variable around in addition to
  298.         // m_bIsProgressive since m_bIsProgressive can change
  299.         // when the file finishes downloading or when the
  300.         // download agent pauses. Since we want to treat files
  301.         // which have a history of being progressive differently
  302.         // than files which don't, we need to keep m_bHasBeenProgressive.
  303.         m_bHasBeenProgressive = TRUE;
  304.         // Update the last file size
  305.         m_ulLastFileSize = ulFileSize;
  306.         // Update the tick count
  307.         m_ulTickAtLastFileSize = ulTick;
  308.     }
  309.     else
  310.     {
  311.         // The filesize is the same. How
  312.         // long has it been the same?
  313.         UINT32 ulDiff = CALCULATE_ELAPSED_TICKS(m_ulTickAtLastFileSize, ulTick);
  314.         // If the file size has been the
  315.         // same for at last m_ulFinishedTime
  316.         // milliseconds, then we assume it has
  317.         // finished downloading
  318.         if (ulDiff > m_ulFinishedTime && m_bIsProgressive)
  319.         {
  320.             MLOG_PD(NULL, "tFile has been %lu bytes for %lu ms. DECLARING FINISHED.n",
  321.                     ulFileSize, ulDiff);
  322.             m_bIsProgressive = FALSE;
  323.         }
  324.     }
  325.     // Did the value of m_bIsProgressive change?
  326.     if (bTmp != m_bIsProgressive)
  327.     {
  328.         // Update the registry statistics
  329.         UpdateRegistryStats();
  330.     }
  331. }
  332. void CProgressiveDownloadMonitor::StatCallback(void* pArg)
  333. {
  334.     if (pArg)
  335.     {
  336.         CProgressiveDownloadMonitor* pObj = (CProgressiveDownloadMonitor*) pArg;
  337.         pObj->MonitorFileSize();
  338.         pObj->ScheduleStatCallback();
  339.     }
  340. }
  341. void CProgressiveDownloadMonitor::ProgCallback(void* pArg)
  342. {
  343.     MLOG_PD(NULL, "CProgressiveDownloadMonitor::ProgCallback(0x%08x) tick=%lun",
  344.             pArg, HX_GET_BETTERTICKCOUNT());
  345.     if (pArg)
  346.     {
  347.         CProgressiveDownloadMonitor* pObj = (CProgressiveDownloadMonitor*) pArg;
  348.         if (pObj->m_pResponse)
  349.         {
  350.             pObj->m_pResponse->ProgressiveCallback();
  351.         }
  352.     }
  353. }
  354. void CProgressiveDownloadMonitor::CheckPreferenceValues(REF(BOOL)   rbMonitorEnabled,
  355.                                                         REF(UINT32) rulStatCallbackInterval,
  356.                                                         REF(UINT32) rulProgCallbackInterval,
  357.                                                         REF(UINT32) rulFinishedTime,
  358.                                                         REF(UINT32) rulFormerProgRetryCount,
  359.                                                         REF(UINT32) rulNotProgRetryCount)
  360. {
  361.     if (m_pContext)
  362.     {
  363.         IHXPreferences* pPrefs = NULL;
  364.         m_pContext->QueryInterface(IID_IHXPreferences, (void**) &pPrefs);
  365.         if (pPrefs)
  366.         {
  367.             ReadPrefBOOL(pPrefs,  "ProgressiveDownload\FileSizeMonitorEnabled",      rbMonitorEnabled);
  368.             ReadPrefINT32(pPrefs, "ProgressiveDownload\FileSizeCheckInterval",       rulStatCallbackInterval);
  369.             ReadPrefINT32(pPrefs, "ProgressiveDownload\FailureRetryInterval",        rulProgCallbackInterval);
  370.             ReadPrefINT32(pPrefs, "ProgressiveDownload\DeclareFinishedDuration",     rulFinishedTime);
  371.             ReadPrefINT32(pPrefs, "ProgressiveDownload\FormerProgressiveRetryCount", rulFormerProgRetryCount);
  372.             ReadPrefINT32(pPrefs, "ProgressiveDownload\NotProgressiveRetryCount",    rulNotProgRetryCount);
  373.             MLOG_PD(NULL,
  374.                     "tFileSizeMonitorEnabled      = %lun"
  375.                     "tFileSizeCheckInterval       = %lun"
  376.                     "tFailureRetryInterval        = %lun"
  377.                     "tDeclareFinishedDuration     = %lun"
  378.                     "tFormerProgressiveRetryCount = %lun"
  379.                     "tNotProgressiveRetryCount    = %lun",
  380.                     rbMonitorEnabled, rulStatCallbackInterval,
  381.                     rulProgCallbackInterval, rulFinishedTime,
  382.                     rulFormerProgRetryCount, rulNotProgRetryCount);
  383.         }
  384.         HX_RELEASE(pPrefs);
  385.     }
  386. }
  387. HX_RESULT CProgressiveDownloadMonitor::InitRegistryStats()
  388. {
  389.     HX_RESULT retVal = HXR_FAIL;
  390.     if (m_pContext && m_pRegistry && m_pDataFile)
  391.     {
  392.         // Get the source registry ID
  393.         IHXRegistryID* pRegistryID = NULL;
  394.         retVal = m_pContext->QueryInterface(IID_IHXRegistryID, (void**) &pRegistryID);
  395.         if (SUCCEEDED(retVal))
  396.         {
  397.             UINT32 ulSourceRegistryID = 0;
  398.             retVal = pRegistryID->GetID(ulSourceRegistryID);
  399.             if (SUCCEEDED(retVal))
  400.             {
  401.                 // Get the source property name - this will
  402.                 // be something like "Statistics.Player0.Source0"
  403.                 IHXBuffer* pSourceName = NULL;
  404.                 retVal = m_pRegistry->GetPropName(ulSourceRegistryID, pSourceName);
  405.                 if (SUCCEEDED(retVal))
  406.                 {
  407.                     // Construct the URL property name
  408.                     CHXString cPropName((const char*) pSourceName->GetBuffer());
  409.                     cPropName += ".URL";
  410.                     // Construct the URL property value
  411.                     CHXString cPropVal("file://");
  412.                     IHXBuffer* pNameBuf = NULL;
  413.                     if (m_pDataFile->Name(pNameBuf))
  414.                     {
  415.                         cPropVal += (const char*) pNameBuf->GetBuffer();
  416.                     }
  417.                     HX_RELEASE(pNameBuf);
  418.                     // Put the URL property value into an IHXBuffer
  419.                     IHXBuffer* pPropVal = NULL;
  420.                     CreateStringBuffer(pPropVal, (const char*) cPropVal, m_pContext);
  421.                     if (pPropVal)
  422.                     {
  423.                         // Does this property already exist?
  424.                         IHXBuffer* pTmp = NULL;
  425.                         if (SUCCEEDED(m_pRegistry->GetStrByName((const char*) cPropName, pTmp)))
  426.                         {
  427.                             // It does already exist
  428.                             //
  429.                             // Set the new value
  430.                             m_pRegistry->SetStrByName((const char*) cPropName, pPropVal);
  431.                             // Get the registry ID
  432.                             m_ulURLRegistryID = m_pRegistry->GetId((const char*) cPropName);
  433.                         }
  434.                         else
  435.                         {
  436.                             // It does not already exist, so create it
  437.                             // and get the registry id at the same time
  438.                             m_ulURLRegistryID = m_pRegistry->AddStr((const char*) cPropName, pPropVal);
  439.                         }
  440.                         HX_RELEASE(pTmp);
  441.                     }
  442.                     HX_RELEASE(pPropVal);
  443.                     // Construct the IsProgressive property name
  444.                     cPropName  = (const char*) pSourceName->GetBuffer();
  445.                     cPropName += ".IsProgressive";
  446.                     // Does this property already exist?
  447.                     INT32 lTmp = 0;
  448.                     if (SUCCEEDED(m_pRegistry->GetIntByName((const char*) cPropName, lTmp)))
  449.                     {
  450.                         // It DOES already exist
  451.                         //
  452.                         // Set the new value
  453.                         m_pRegistry->SetIntByName((const char*) cPropName, (m_bIsProgressive ? 1 : 0));
  454.                         // Get the registry id
  455.                         m_ulIsProgRegistryID = m_pRegistry->GetId((const char*) cPropName);
  456.                     }
  457.                     else
  458.                     {
  459.                         // It does NOT already exist
  460.                         //
  461.                         // Create the IsProgressive property and get
  462.                         // the registry id at the same time
  463.                         m_ulIsProgRegistryID = m_pRegistry->AddInt((const char*) cPropName,
  464.                                                                    (m_bIsProgressive ? 1 : 0));
  465.                     }
  466.                 }
  467.                 HX_RELEASE(pSourceName);
  468.             }
  469.         }
  470.         HX_RELEASE(pRegistryID);
  471.     }
  472.     return retVal;
  473. }
  474. void CProgressiveDownloadMonitor::UpdateRegistryStats()
  475. {
  476.     MLOG_PD(NULL, "CProgressiveDownloadMonitor::UpdateRegistryStats() this=0x%08xn", this);
  477.     // Right now the only thing we are updating
  478.     // is the IsProgressive property. We assume
  479.     // that the URL property will never need to
  480.     // change during playback.
  481.     if (m_pRegistry && m_ulIsProgRegistryID)
  482.     {
  483.         m_pRegistry->SetIntById(m_ulIsProgRegistryID, (m_bIsProgressive ? 1 : 0));
  484.     }
  485. }
  486. void CProgressiveDownloadMonitor::ScheduleStatCallback()
  487. {
  488.     if (m_pStatCallback && m_bMonitorEnabled)
  489.     {
  490.         MLOG_PD(NULL, "CProgressiveDownloadMonitor::ScheduleStatCallback() this=0x%08x m_ulCurStatInterval=%lun",
  491.                 this, m_ulCurStatInterval);
  492.         m_pStatCallback->ScheduleRelative(m_pScheduler, m_ulCurStatInterval);
  493.         // We start off with a small stat interval
  494.         // and double the interval every time until
  495.         // we reach m_ulStatCallbackInterval
  496.         if (m_ulCurStatInterval < m_ulStatCallbackInterval)
  497.         {
  498.             m_ulCurStatInterval *= 2;
  499.             if (m_ulCurStatInterval > m_ulStatCallbackInterval)
  500.             {
  501.                 m_ulCurStatInterval = m_ulStatCallbackInterval;
  502.             }
  503.         }
  504.     }
  505. }