sspayld.cpp
Upload User: dangjiwu
Upload Date: 2013-07-19
Package Size: 42019k
Code Size: 17k
Category:

Symbian

Development Platform:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: sspayld.cpp,v 1.3.8.1 2004/07/09 01:55:14 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hxtypes.h"
  50. #include "hxcom.h"
  51. #include "hxassert.h"
  52. #include "hxslist.h"
  53. #include "hxcomm.h"
  54. #include "ihxpckts.h"
  55. #include "netbyte.h"
  56. #include "sspayld.h"
  57. #define DEFAULT_MAX_PACKET_SIZE 1500
  58. SimpleSegmentPayloadFormat::SimpleSegmentPayloadFormat()
  59. : m_lRefCount(0)
  60. , m_pCommonClassFactory(NULL)
  61. , m_pStreamHeader(NULL)
  62. , m_bPacketize(FALSE)
  63. , m_ulMaxSegmentSize(DEFAULT_MAX_PACKET_SIZE)
  64. , m_ulTotalSegments(0)
  65. , m_pSegmentedPackets(NULL)
  66. , m_pAssembledPacket(NULL)
  67. , m_bBigEndian(FALSE)
  68. {
  69.     m_pSegmentedPackets = new CHXSimpleList();
  70.     m_bBigEndian = TestBigEndian();
  71. }
  72. SimpleSegmentPayloadFormat::~SimpleSegmentPayloadFormat()
  73. {
  74.     Reset();
  75.     HX_DELETE(m_pSegmentedPackets);
  76.     HX_RELEASE(m_pCommonClassFactory);
  77. }
  78. // *** IUnknown methods ***
  79. /////////////////////////////////////////////////////////////////////////
  80. //  Method:
  81. //  IUnknown::QueryInterface
  82. //  Purpose:
  83. //  Implement this to export the interfaces supported by your
  84. //  object.
  85. //
  86. STDMETHODIMP
  87. SimpleSegmentPayloadFormat::QueryInterface(REFIID riid, void** ppvObj)
  88. {
  89.     QInterfaceList  qiList[] =
  90.     {
  91. { GET_IIDHANDLE(IID_IUnknown), this},
  92. { GET_IIDHANDLE(IID_IHXPayloadFormatObject), (IHXPayloadFormatObject*)this},
  93.     };
  94.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  95. }
  96. /////////////////////////////////////////////////////////////////////////
  97. //  Method:
  98. //  IUnknown::AddRef
  99. //  Purpose:
  100. //  Everyone usually implements this the same... feel free to use
  101. //  this implementation.
  102. //
  103. STDMETHODIMP_(ULONG32)
  104. SimpleSegmentPayloadFormat::AddRef()
  105. {
  106.     return InterlockedIncrement(&m_lRefCount);
  107. }
  108. /////////////////////////////////////////////////////////////////////////
  109. //  Method:
  110. //  IUnknown::Release
  111. //  Purpose:
  112. //  Everyone usually implements this the same... feel free to use
  113. //  this implementation.
  114. //
  115. STDMETHODIMP_(ULONG32)
  116. SimpleSegmentPayloadFormat::Release()
  117. {
  118.     if ( InterlockedDecrement(&m_lRefCount) > 0 )
  119.     {
  120.         return m_lRefCount;
  121.     }
  122.     delete this;
  123.     return 0;
  124. }
  125. STDMETHODIMP
  126. SimpleSegmentPayloadFormat::Init( IUnknown* pContext,
  127.                                   BOOL bPacketize )
  128. {
  129.     HX_ASSERT(pContext);
  130.     if ( !pContext )
  131.     {
  132.         return HXR_FAIL;
  133.     }
  134.     HX_RELEASE(m_pCommonClassFactory);
  135.     m_pCommonClassFactory = NULL;
  136.     if ( HXR_OK != pContext->QueryInterface( IID_IHXCommonClassFactory,
  137.                                              (void**) &m_pCommonClassFactory )
  138.        )
  139.     {
  140.         return HXR_FAIL;
  141.     }
  142.     m_bPacketize = bPacketize;
  143.     return HXR_OK;
  144. }
  145. STDMETHODIMP
  146. SimpleSegmentPayloadFormat::Reset()
  147. {
  148.     // Reset() is presumed not to be the complete opposite of Init();
  149.     // We reset stream information but keep our context and packetization
  150.     // orientation until the next Init()
  151.     HX_RELEASE( m_pStreamHeader );
  152.     m_pStreamHeader = NULL;
  153.     m_ulMaxSegmentSize = 0;
  154.     HX_RELEASE( m_pAssembledPacket );
  155.     m_pAssembledPacket = NULL;
  156.     return Flush();
  157. }
  158. STDMETHODIMP
  159. SimpleSegmentPayloadFormat::SetStreamHeader( IHXValues* pHeader )
  160. {
  161.     HX_ASSERT( pHeader );
  162.     if ( !pHeader )
  163.     {
  164.         return HXR_FAIL;
  165.     }
  166.     HX_RELEASE( m_pStreamHeader );
  167.     m_pStreamHeader = pHeader;
  168.     m_pStreamHeader->AddRef();
  169.     if ( HXR_OK != m_pStreamHeader->GetPropertyULONG32( "MaxPacketSize", m_ulMaxSegmentSize ) )
  170.     {
  171.         m_ulMaxSegmentSize = DEFAULT_MAX_PACKET_SIZE;
  172.     }
  173.     return HXR_OK;
  174. }
  175. STDMETHODIMP
  176. SimpleSegmentPayloadFormat::GetStreamHeader( REF(IHXValues*) pHeader )
  177. {
  178.     HX_ASSERT( m_pStreamHeader );
  179.     pHeader = m_pStreamHeader;
  180.     pHeader->AddRef();
  181.     return HXR_OK;
  182. }
  183. STDMETHODIMP
  184. SimpleSegmentPayloadFormat::SetPacket( IHXPacket* pPacket )
  185. {
  186.     HX_ASSERT(pPacket);
  187.     if ( !pPacket )
  188.     {
  189.         return HXR_FAIL;
  190.     }
  191.     if ( m_bPacketize )
  192.     {
  193.         // Segment the packet here rather than in GetPacket(), on
  194.         // the assumption that GetPacket() is a time sensitive function:
  195.         // We implicitly allow multiple SetPackets() before a GetPacket()
  196.         // in this case; it is up to the client to realize there are multiple
  197.         // segmented packets in our queue.
  198.         IHXBuffer* pPacketBuffer = pPacket->GetBuffer();
  199.         HX_ASSERT( pPacketBuffer );
  200.         if ( !pPacketBuffer )
  201.         {
  202.             return HXR_FAIL;
  203.         }
  204.         UCHAR* pPacketBufferData = pPacketBuffer->GetBuffer();
  205.         UINT32 uiBytesRemaining = pPacketBuffer->GetSize();
  206.         // An unsafe cast: to retain backwards compatibility, not much we can do about it.
  207.         // We could implement a high segment count as an escape sequence; this would break
  208.         // however, in the unlikely event someone wanted to segment a packet into 65535
  209.         // chunks using deployed code (CPNFragment).  To be investigated if the priority ever
  210.         // becomes high.
  211.         m_ulTotalSegments = (unsigned short) ( pPacketBuffer->GetSize() / m_ulMaxSegmentSize );
  212.         if ( pPacketBuffer->GetSize() % m_ulMaxSegmentSize )
  213.         {
  214.             m_ulTotalSegments++;
  215.         }
  216.         IHXBuffer* pSegmentBuffer;
  217.         IHXPacket* pSegmentPacket;
  218.         for ( int i = 0; uiBytesRemaining; i++ )
  219.         {
  220.             if ( HXR_OK != m_pCommonClassFactory->CreateInstance( IID_IHXBuffer,
  221.                                                                   (void**) &pSegmentBuffer )
  222.                )
  223.             {
  224.                 Flush();
  225.                 HX_RELEASE( pPacketBuffer );
  226.                 return HXR_OUTOFMEMORY;
  227.             }
  228.             if ( HXR_OK != m_pCommonClassFactory->CreateInstance( IID_IHXPacket,
  229.                                                                   (void**) &pSegmentPacket )
  230.                )
  231.             {
  232.                 Flush();
  233.                 HX_RELEASE( pSegmentBuffer );
  234.                 HX_RELEASE( pPacketBuffer );
  235.                 return HXR_OUTOFMEMORY;
  236.             }
  237.             pSegmentBuffer->SetSize( sizeof(SEGMENTHEADER) + (uiBytesRemaining > m_ulMaxSegmentSize) ? m_ulMaxSegmentSize : uiBytesRemaining );
  238.             LPSEGMENTHEADER pSegmentHeader = (LPSEGMENTHEADER) pSegmentBuffer->GetBuffer();
  239.             pSegmentHeader->ulOffset = i * ( m_ulMaxSegmentSize );
  240.             pSegmentHeader->usIndex = i;
  241.             pSegmentHeader->usTotalSegments = m_ulTotalSegments;
  242.             if ( !m_bBigEndian )
  243.             {
  244.                 SwapDWordBytes(&pSegmentHeader->ulOffset, 1);
  245.                 SwapWordBytes(&pSegmentHeader->usIndex, 1);
  246.                 SwapWordBytes(&pSegmentHeader->usTotalSegments, 1);
  247.             }
  248.             memcpy( (UCHAR*) pSegmentHeader + sizeof(SEGMENTHEADER), /* Flawfinder: ignore */
  249.                     pPacketBufferData + pSegmentHeader->ulOffset,
  250.                     pSegmentBuffer->GetSize() - sizeof(SEGMENTHEADER)
  251.                   );
  252.             uiBytesRemaining -= pSegmentBuffer->GetSize() - sizeof(SEGMENTHEADER);;
  253.             pSegmentPacket->Set( pSegmentBuffer,
  254.                                  pPacket->GetTime(),
  255.                                  pPacket->GetStreamNumber(),
  256.                                  pPacket->GetASMFlags(),
  257.                                  pPacket->GetASMRuleNumber()
  258.                                );
  259.             HX_RELEASE( pSegmentBuffer );
  260.             m_pSegmentedPackets->AddTail( pSegmentPacket );
  261.         }
  262.         HX_RELEASE( pPacketBuffer );
  263.     }
  264.     else
  265.     {
  266.         // This PayloadFormat does not return incomplete data;
  267.         // The client is assumed to be able to deal with lost data quantums
  268.         // of the size of m_ulPacketSize:
  269.         if ( pPacket->IsLost() )
  270.         {
  271.             Flush();
  272.             return HXR_OK;
  273.         }
  274.         IHXBuffer* pPacketBuffer = pPacket->GetBuffer();
  275.         UINT16 usSegment = ( (LPSEGMENTHEADER) pPacketBuffer->GetBuffer() )->usIndex;
  276.         if ( !m_bBigEndian )
  277.         {
  278.             SwapWordBytes( &usSegment, 1 );
  279.         }
  280.         HX_RELEASE( pPacketBuffer );
  281.         // Missing/lost segments?
  282.         if (usSegment != m_pSegmentedPackets->GetCount())
  283.         {
  284.             // Since we flush on lost packets, a non-zero segment list
  285.             // indicates a *missing* packet (bug in the core)
  286.             HX_ASSERT(m_pSegmentedPackets->GetCount() == 0 && "Missing segments!");
  287.             Flush();
  288.             return HXR_OK;
  289.         }
  290.         pPacket->AddRef();
  291.         m_pSegmentedPackets->AddTail( pPacket );
  292.         // New frame?
  293.         if ( usSegment == 0 )
  294.         {
  295.             IHXBuffer* pFirstBuffer = pPacket->GetBuffer();
  296.             HX_ASSERT( pFirstBuffer );
  297.             m_ulTotalSegments = ( (LPSEGMENTHEADER) pFirstBuffer->GetBuffer() )->usTotalSegments;
  298.             if ( !m_bBigEndian )
  299.             {
  300.                 SwapWordBytes( &m_ulTotalSegments, 1 );
  301.             }
  302.             HX_RELEASE( pFirstBuffer );
  303.             if (m_ulTotalSegments == 0)
  304.             {
  305.                 // No segments, eh?
  306.                 HX_ASSERT(FALSE && "Segment count zero - packetizer error!");
  307.                 Flush();
  308.                 return HXR_OK;
  309.             }
  310.         }
  311.         // Sort and reconstruct the packet here, rather than in GetPacket(), on
  312.         // the assumption that GetPacket() is a time sensitive function:
  313.         if ( m_pSegmentedPackets->GetCount() == m_ulTotalSegments )
  314.         {
  315.             // We use a simple O(n) reconstruction here (no sorting)
  316.             UINT32 uiPacketSize = 0;
  317.             IHXBuffer* pSegmentBuffer = NULL;
  318.             UCHAR* pSegmentBufferData = NULL;
  319.             // Find packet size and swap headers:
  320.             for ( CHXSimpleList::Iterator maxIterator = m_pSegmentedPackets->Begin();
  321.                 maxIterator != m_pSegmentedPackets->End();
  322.                 ++maxIterator )
  323.             {
  324.                 pSegmentBuffer = ( (IHXPacket*) *maxIterator )->GetBuffer();
  325.                 pSegmentBufferData = pSegmentBuffer->GetBuffer();
  326.                 if ( !m_bBigEndian )
  327.                 {
  328.                     SwapDWordBytes( &( (LPSEGMENTHEADER) pSegmentBufferData )->ulOffset, 1 );
  329.                 }
  330.                 if ( ( (LPSEGMENTHEADER) pSegmentBufferData )->ulOffset + pSegmentBuffer->GetSize() > uiPacketSize )
  331.                 {
  332.                     uiPacketSize = ( (LPSEGMENTHEADER) pSegmentBufferData )->ulOffset + pSegmentBuffer->GetSize();
  333.                 }
  334.                 HX_RELEASE(pSegmentBuffer);
  335.             }
  336.             uiPacketSize -= sizeof( SEGMENTHEADER );
  337.             // An assembled packet should have been collected by this point; we only assemble
  338.             // one packet at a time, for now, for simplicity.
  339.             HX_ASSERT( !m_pAssembledPacket );
  340.             HX_RELEASE( m_pAssembledPacket );
  341.             m_pAssembledPacket = NULL;
  342.             // Create our assembled packet, buffer:
  343.             IHXBuffer* pPacketBuffer = NULL;
  344.             if ( HXR_OK != m_pCommonClassFactory->CreateInstance( IID_IHXBuffer,
  345.                                                                   (void**) &pPacketBuffer )
  346.                )
  347.             {
  348.                 Flush();
  349.                 return HXR_FAIL;
  350.             }
  351.             if ( HXR_OK != m_pCommonClassFactory->CreateInstance( IID_IHXPacket,
  352.                                                                   (void**) &m_pAssembledPacket )
  353.                )
  354.             {
  355.                 Flush();
  356.                 HX_RELEASE( pPacketBuffer );
  357.                 return HXR_FAIL;
  358.             }
  359.             pPacketBuffer->SetSize( uiPacketSize );
  360.             IHXPacket* pPacketDetails = ( (IHXPacket*) m_pSegmentedPackets->GetHead() );
  361.             m_pAssembledPacket->Set(pPacketBuffer,
  362.                                     pPacketDetails->GetTime(),
  363.                                     pPacketDetails->GetStreamNumber(),
  364.                                     pPacketDetails->GetASMFlags(),
  365.                                     pPacketDetails->GetASMRuleNumber()
  366.                                    );
  367.             // This reconstruction approach may not assemble in segment order, but the
  368.             // performance penalty is small, and it keeps the code simple.  Using ulOffset
  369.             // also allows clever datatypes/compatible payload formatters to insert gaps in
  370.             // the buffer in which the renders could write data for their own bizzare
  371.             // purposes (use at your own peril).
  372.             UCHAR* pPacketBufferData = pPacketBuffer->GetBuffer();
  373.             UINT32 ulPacketBufferSize = pPacketBuffer->GetSize();
  374.             HX_RELEASE(pPacketBuffer);
  375.             IHXPacket* pSegmentPacket = NULL;
  376.             while ( !m_pSegmentedPackets->IsEmpty() )
  377.             {
  378.                 pSegmentPacket = (IHXPacket*) m_pSegmentedPackets->RemoveHead();
  379.                 HX_ASSERT( pSegmentPacket );
  380.                 pSegmentBuffer = pSegmentPacket->GetBuffer();
  381.                 HX_ASSERT( pSegmentBuffer );
  382.                 pSegmentBufferData = pSegmentBuffer->GetBuffer();
  383.                 UINT32 ulMaxCopyBytes = ulPacketBufferSize - ( (LPSEGMENTHEADER) pSegmentBufferData )->ulOffset;
  384.                 UINT32 ulBytesToCopy = pSegmentBuffer->GetSize() - sizeof(SEGMENTHEADER);
  385.                 if (ulBytesToCopy > ulMaxCopyBytes) ulBytesToCopy = ulMaxCopyBytes;
  386.                 memcpy( pPacketBufferData + ( (LPSEGMENTHEADER) pSegmentBufferData )->ulOffset, /* Flawfinder: ignore */
  387.                         pSegmentBufferData + sizeof(SEGMENTHEADER),
  388.                         ulBytesToCopy);
  389.                 HX_RELEASE( pSegmentBuffer );
  390.                 HX_RELEASE( pSegmentPacket );
  391.             }
  392.         }
  393.     }
  394.     return HXR_OK;
  395. }
  396. STDMETHODIMP
  397. SimpleSegmentPayloadFormat::GetPacket( REF(IHXPacket*) pPacket )
  398. {
  399.     pPacket = NULL;
  400.     if ( m_bPacketize )
  401.     {
  402.         if ( m_pSegmentedPackets->IsEmpty() )
  403.         {
  404.             return HXR_UNEXPECTED;
  405.         }
  406.         else
  407.         {
  408.             pPacket = (IHXPacket*) m_pSegmentedPackets->RemoveHead();
  409.         }
  410.     }
  411.     else
  412.     {
  413.         if ( m_pAssembledPacket )
  414.         {
  415.             pPacket = m_pAssembledPacket;
  416.             m_pAssembledPacket = NULL;
  417.         }
  418.         else
  419.         {
  420.             return HXR_INCOMPLETE;
  421.         }
  422.     }
  423.     return HXR_OK;
  424. }
  425. STDMETHODIMP
  426. SimpleSegmentPayloadFormat::Flush()
  427. {
  428.     // Release all of our segment packets; but keep any assembled
  429.     while ( !m_pSegmentedPackets->IsEmpty() )
  430.     {
  431.         IHXPacket* pPacket = (IHXPacket*) m_pSegmentedPackets->RemoveHead();
  432.         HX_RELEASE(pPacket);
  433.     }
  434.     m_ulTotalSegments = 0;
  435.     return HXR_OK;
  436. }