Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
IMAAudioRTP/Sources/RTPRssmIMAAudio.c
/* |
File: RTPRssmIMAAudio.c |
Contains: Definition of IMA Audio RTPReassembler |
Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved. |
OVERVIEW |
QuickTime Streaming software uses an RTPReassembler to extract sample data |
from incoming RTP packets. A base RTPReassembler defined by QuickTime |
Streaming does much of the work of reassembling. A derived RTPReassembler |
extends the base to interpret a specific RTP payload format, to select an |
appropriate StreamHandler to process reassembled sample data, and to |
handle network packet loss. |
This reassembler extends or fully implements the following interface and |
delegates all other calls to its base. |
STANDARD COMPONENT INTERFACE |
---------------------------- |
CallComponentOpen() Allocate and initialize storage for |
instance variables. |
CallComponentClose() Reverse the effects of |
CallComponentOpen(). |
CallComponentVersion() Return the instance's version. |
CallComponentTarget() Update the instance's inheritance graph. |
RTP REASSEMBLER INTERFACE |
------------------------------ |
RTPRssmInitialize() Prepare to reassemble sample data. |
RTPRssmComputeChunkSize() Determine the size of buffer needed for |
the data in a list of network packets. |
RTPRssmAdjustPacketParams() Adjust fields of an RTPRssmPacket to |
reflect the properties of its payload. |
RTPRssmCopyDataToChunk() Copy sample data from a packet list to |
a data buffer. |
RTPRssmSendPacketList() Prepare to process or discard a list of |
packets. |
RTPRssmHasCharacteristic() Indicate whether the reassembler has the |
specified characteristic. |
RTPRssmReset() End processing of the current stream of |
network packets. |
*/ |
/* --------------------------------------------------------------------------- |
* H E A D E R S |
* --------------------------------------------------------------------------- |
*/ |
#include "RTPRssmIMAAudio.h" |
#include "RTPRssmIMAAudioResources.h" |
#include <FixMath.h> |
#include <string.h> |
/* --------------------------------------------------------------------------- |
* R T P R E A S S E M B L E R P R O T O T Y P E S |
* --------------------------------------------------------------------------- |
* |
* QTStreamingComponents.k.h uses these macros to declare prototypes for |
* the RTPReassembler calls defined in this file. |
* |
*/ |
#define RTPRSSM_BASENAME() RTPRssmIMAAudio_ |
#define RTPRSSM_GLOBALS() RTPRssmIMAAudioInstanceData ** |
#include <QTStreamingComponents.k.h> |
/* --------------------------------------------------------------------------- |
* C O M P O N E N T D I S P A T C H H E L P E R |
* --------------------------------------------------------------------------- |
* |
* ComponentDispatchHelper.c uses these macros to define a dispatcher and to |
* declare prototypes for the core component calls defined in this file. For |
* Mac OS, it defines the routine descriptor that serves as the component |
* entry point. The name of the routine descriptor is the macro expansion of |
* |
* CALLCOMPONENT_BASENAME()##ComponentDispatchRD |
* |
* The name of the dispatcher is the macro expansion of |
* |
* CALLCOMPONENT_BASENAME()##ComponentDispatch |
* |
*/ |
#define CALLCOMPONENT_BASENAME() RTPRSSM_BASENAME() |
#define CALLCOMPONENT_GLOBALS() RTPRSSM_GLOBALS() storage |
#define COMPONENT_DISPATCH_FILE "RTPRssmIMAAudioDispatch.h" |
#define COMPONENT_C_DISPATCHER 1 |
#define COMPONENT_UPP_SELECT_ROOT() RTPRssm |
#define GET_DELEGATE_COMPONENT() ( ( **storage ).itsBase ) |
#include <ComponentDispatchHelper.c> |
#pragma mark * INTERNAL IMPLEMENTATION |
#pragma mark - |
/* --------------------------------------------------------------------------- |
* I N T E R N A L I M P L E M E N T A T I O N |
* --------------------------------------------------------------------------- |
*/ |
/* --------------------------------------------------------------------------- |
* __GetNewSampleDescription() |
* --------------------------------------------------------------------------- |
* |
* Create a new SampleDescription for this reassembler's payload using the |
* given payload attributes. |
* |
*/ |
static |
ComponentResult |
__GetNewSampleDescription( |
const IMAAudioPayload * inPayloadAttributes, |
SampleDescriptionHandle * outDescription ) |
{ |
ComponentResult theResult = noErr; |
SoundDescriptionHandle theDescription; |
theDescription = |
REINTERPRET_CAST( SoundDescriptionHandle )( |
NewHandleClear( sizeof( **theDescription ) ) ); |
if( theDescription ) |
{ |
*outDescription = REINTERPRET_CAST( SampleDescriptionHandle )( theDescription ); |
( **theDescription ).descSize = sizeof( **theDescription ); |
( **theDescription ).dataFormat = kIMAAudioDataFormat; |
( **theDescription ).resvd1 = 0; |
( **theDescription ).resvd2 = 0; |
( **theDescription ).dataRefIndex = 0; |
( **theDescription ).version = 0; |
( **theDescription ).revlevel = 0; |
( **theDescription ).vendor = kComponentManufactureType; |
( **theDescription ).numChannels = |
IMAAudioPayloadChannelCount( inPayloadAttributes ); |
( **theDescription ).sampleSize = 16; |
( **theDescription ).compressionID = 0; |
( **theDescription ).packetSize = 0; |
( **theDescription ).sampleRate = |
IMAAudioPayloadSampleRate( inPayloadAttributes );; |
} |
else |
{ |
*outDescription = 0; |
theResult = MemError(); |
if( theResult == noErr ) |
theResult = memFullErr; |
} |
return( theResult ); |
} |
/* --------------------------------------------------------------------------- |
* __GetPayload() |
* --------------------------------------------------------------------------- |
* |
* Return a pointer to the start of a packet's payload. |
* |
*/ |
static |
IMAAudioPayload * |
__GetPayload( |
RTPRssmPacket * inPacket ) |
{ |
return( |
REINTERPRET_CAST( IMAAudioPayload * )( |
&inPacket->streamBuffer->rptr[ inPacket->transportHeaderLength ] ) ); |
} |
/* --------------------------------------------------------------------------- |
* __FillMissingData() |
* --------------------------------------------------------------------------- |
* |
* Synthesize data for missing audio frames. This implementation zeros out |
* missing frames to synthesize silence. |
*/ |
static |
void |
__FillMissingData( |
RTPRssmPacket * inPackets, |
UInt16 inGroupStartSequenceNumber, |
UInt32 inInterleaveCount, |
SHChunkRecord * inChunk ) |
{ |
IMAAudioFrame * theFrames; |
UInt32 theFrameCount; |
UInt16 theExpectedSequenceNumber; |
RTPRssmPacket * thePacket; |
UInt16 theMissingPacketCount; |
UInt32 theIndex; |
/* |
For now, this function is just for looks, as it doesn't actually |
produce the desired audible effect. The problem is that the |
decompressor doesn't use all data in each frame, so it doesn't |
necessarily decode zeroed frames as silence, and inserting zeroed |
frames into the data stream usually distorts the decoding of some |
subsequent frames. |
IMPORTANT The sequence number computations in this function work |
because the packets are in order and the separation |
between the packets is guaranteed to be within the |
precision of the RTP sequence number field (i.e., less |
than 16 bits, or 65536 packets). When computing with |
sequence numbers of packets that might be separated by |
more than 65535 packets, a reassembler must extend the |
precision of the sequence numbers, for instance by |
using the inNumWraparounds parameter of |
RTPRssmHandleNewPacket() or by using the timeStamp |
field of RTPRssmPacket structures. |
*/ |
theFrames = |
REINTERPRET_CAST( IMAAudioFrame * )( CONST_CAST( UInt8 * )( inChunk->dataPtr ) ); |
theFrameCount = inChunk->dataSize / sizeof( IMAAudioFrame ); |
theExpectedSequenceNumber = inGroupStartSequenceNumber; |
for( thePacket = inPackets; thePacket; thePacket = thePacket->next ) |
{ |
theMissingPacketCount = thePacket->sequenceNum - theExpectedSequenceNumber; |
if( theMissingPacketCount ) |
{ |
for( |
theIndex = theExpectedSequenceNumber - inGroupStartSequenceNumber; |
theIndex < theFrameCount; theIndex += inInterleaveCount ) |
{ |
memset( |
&theFrames[ theIndex ], 0, |
theMissingPacketCount * sizeof( IMAAudioFrame ) ); |
} |
} |
theExpectedSequenceNumber = thePacket->sequenceNum + 1; |
} |
theMissingPacketCount = |
inGroupStartSequenceNumber + inInterleaveCount - theExpectedSequenceNumber; |
if( theMissingPacketCount ) |
{ |
for( |
theIndex = theExpectedSequenceNumber - inGroupStartSequenceNumber; |
theIndex < theFrameCount; theIndex += inInterleaveCount ) |
{ |
memset( |
&theFrames[ theIndex ], 0, |
theMissingPacketCount * sizeof( IMAAudioFrame ) ); |
} |
} |
} |
/* --------------------------------------------------------------------------- |
* __InterleaveGroupDataSize() |
* --------------------------------------------------------------------------- |
* |
* Compute the number of octets of data in the interleave group to which the |
* given packet belongs. |
* |
*/ |
static |
UInt32 |
__InterleaveGroupDataSize( |
RTPRssmPacket * inPacket ) |
{ |
UInt32 theResult; |
const IMAAudioPayload * thePayload; |
UInt32 theInterleaveCount; |
UInt32 theInterleaveIndex; |
UInt32 theInterleaveTail; |
thePayload = __GetPayload( inPacket ); |
theInterleaveCount = IMAAudioPayloadInterleaveCount( thePayload ); |
theInterleaveIndex = IMAAudioPayloadInterleaveIndex( thePayload ); |
theInterleaveTail = IMAAudioPayloadInterleaveTail( thePayload ); |
theResult = theInterleaveCount * inPacket->dataLength; |
if( theInterleaveIndex <= theInterleaveTail ) |
{ |
theResult -= |
sizeof( IMAAudioFrame ) * ( theInterleaveCount - theInterleaveTail - 1 ); |
} |
else |
{ |
theResult += sizeof( IMAAudioFrame ) * ( theInterleaveTail + 1 ); |
} |
return( theResult ); |
} |
#pragma mark - |
#pragma mark * STANDARD COMPONENT INTERFACE |
#pragma mark - |
/* --------------------------------------------------------------------------- |
* S T A N D A R D C O M P O N E N T I N T E R F A C E |
* --------------------------------------------------------------------------- |
*/ |
/* --------------------------------------------------------------------------- |
* + CallComponentOpen() implementation |
* --------------------------------------------------------------------------- |
* |
* Allocate and initialize storage for instance variables. When a |
* reassembler is opened, it is not always called to reassemble data, so this |
* function doesn't perform any allocations or time-consuming operations that |
* are needed only to reassemble sample data. The RTPRssmInitialize() |
* implementation performs such operations. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_Open( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
ComponentInstance self ) |
{ |
ComponentResult theResult = noErr; |
RTPReassembler theBase; |
inGlobals = |
REINTERPRET_CAST( RTPRssmIMAAudioInstanceData ** )( |
NewHandleClear( sizeof( **inGlobals ) ) ); |
if( inGlobals ) |
{ |
( **inGlobals ).itself = self; |
( **inGlobals ).itsFinalDerivation = self; |
SetComponentInstanceStorage( self, REINTERPRET_CAST( Handle )( inGlobals ) ); |
theResult = |
OpenADefaultComponent( |
kRTPReassemblerType, kRTPBaseReassemblerType, &theBase ); |
if( theResult == noErr ) |
{ |
( **inGlobals ).itsBase = theBase; |
theResult = CallComponentTarget( ( **inGlobals ).itsBase, self ); |
} |
} |
else |
{ |
theResult = MemError(); |
if( theResult == noErr ) |
theResult = memFullErr; |
} |
return( theResult ); |
} |
/* --------------------------------------------------------------------------- |
* + CallComponentClose() implementation |
* --------------------------------------------------------------------------- |
* |
* Reverse the effects of the CallComponentOpen() implementation. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_Close( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
ComponentInstance self ) |
{ |
#pragma unused( self ) |
if( inGlobals ) |
{ |
if( ( **inGlobals ).itsBase ) |
CloseComponent( ( **inGlobals ).itsBase ); |
DisposeHandle( REINTERPRET_CAST( Handle )( inGlobals ) ); |
} |
return( noErr ); |
} |
/* --------------------------------------------------------------------------- |
* + CallComponentVersion() implementation |
* --------------------------------------------------------------------------- |
* |
* Return the instance's version. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_Version( |
RTPRssmIMAAudioInstanceData ** inGlobals ) |
{ |
#pragma unused( inGlobals ) |
return( kComponentVersion ); |
} |
/* --------------------------------------------------------------------------- |
* + CallComponentTarget() implementation |
* --------------------------------------------------------------------------- |
* |
* Update the instance's inheritance graph with a new most-derived instance. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_Target( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
ComponentInstance target ) |
{ |
ComponentResult theResult; |
if( ( **inGlobals ).itsBase ) |
theResult = CallComponentTarget( ( **inGlobals ).itsBase, target ); |
else |
theResult = noErr; |
if( theResult == noErr ) |
( **inGlobals ).itsFinalDerivation = target; |
return( theResult ); |
} |
#pragma mark - |
#pragma mark * RTP REASSEMBLER INTERFACE |
#pragma mark - |
/* --------------------------------------------------------------------------- |
* R T P R E A S S E M B L E R I N T E R F A C E |
* --------------------------------------------------------------------------- |
*/ |
/* --------------------------------------------------------------------------- |
* + RTPRssmInitialize() implementation |
* --------------------------------------------------------------------------- |
* |
* Prepare to reassemble sample data. This implementation initializes |
* instance variables that represent the payload state, opens a new |
* StreamHandler to process reassembled sample data, and sets options that |
* determine how its base reassembler handles network packets. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_Initialize( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
RTPRssmInitParams * inInitParams ) |
{ |
ComponentResult theResult = noErr; |
IMAAudioPayload thePayloadAttributes; |
SampleDescriptionHandle theDescription; |
if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPRssmInitializeSelect ) ) |
theResult = RTPRssmInitialize( ( **inGlobals ).itsBase, inInitParams ); |
if( theResult == noErr ) |
{ |
IMAAudioPayloadInitialize( &thePayloadAttributes ); |
theResult = |
__GetNewSampleDescription( &thePayloadAttributes, &theDescription ); |
( **inGlobals ).itsPayloadAttributes = thePayloadAttributes; |
if( theResult == noErr ) |
{ |
theResult = |
RTPRssmNewStreamHandler( |
( **inGlobals ).itsFinalDerivation, SoundMediaType, |
theDescription, kIMAAudioPayloadRTPTimeScale, NULL ); |
DisposeHandle( REINTERPRET_CAST( Handle )( theDescription ) ); |
if( theResult == noErr ) |
{ |
theResult = |
RTPRssmSetCapabilities( |
( **inGlobals ).itsFinalDerivation, |
kRTPRssmTrackLostPacketsFlag | kRTPRssmQueueAndUseMarkerBitFlag, |
-1L ); |
} |
} |
} |
return( theResult ); |
} |
/* --------------------------------------------------------------------------- |
* + RTPRssmComputeChunkSize() implementation |
* --------------------------------------------------------------------------- |
* |
* Use the packet list to determine the size of the data buffer needed to |
* pass data from these network packets to the StreamHandler. |
* |
* For this reassembler, the chunk size is the audio data size for the entire |
* interleave group to which the given packets belong. (The data is |
* packetized such that the base reassembler can automatically group |
* incoming packets by interleave group, so the packets in the list will be |
* all those packets, and only those packets, from a single interleave |
* group.) The size cannot be computed by summing the data sizes of network |
* packets received, since some packets might be lost. Instead, the size is |
* determnined, through a call to __InterleaveGroupDataSize() defined above, |
* by inspecting the payload header and data size of the first packet. |
* |
* This function also updates the StreamHandler's SampleDescription when the |
* sample rate or channel count changes. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_ComputeChunkSize( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
RTPRssmPacket * inPacketListHead, |
SInt32 inFlags, |
UInt32 * outChunkDataSize ) |
{ |
#pragma unused( inFlags ) |
ComponentResult theResult = noErr; |
const IMAAudioPayload * thePayload; |
UInt32 theChannelCount; |
UnsignedFixed theSampleRate; |
SampleDescriptionHandle theDescription; |
thePayload = __GetPayload( inPacketListHead ); |
theChannelCount = IMAAudioPayloadChannelCount( &( **inGlobals ).itsPayloadAttributes ); |
theSampleRate = IMAAudioPayloadSampleRate( &( **inGlobals ).itsPayloadAttributes ); |
if( |
IMAAudioPayloadChannelCount( thePayload ) != theChannelCount || |
IMAAudioPayloadSampleRate( thePayload ) != theSampleRate ) |
{ |
theResult = __GetNewSampleDescription( thePayload, &theDescription ); |
if( theResult == noErr ) |
{ |
theResult = |
RTPRssmSetSampleDescription( |
( **inGlobals ).itsFinalDerivation, theDescription ); |
if( theResult == noErr ) |
( **inGlobals ).itsPayloadAttributes = *thePayload; |
DisposeHandle( REINTERPRET_CAST( Handle )( theDescription ) ); |
} |
} |
*outChunkDataSize = __InterleaveGroupDataSize( inPacketListHead ); |
return( theResult ); |
} |
/* --------------------------------------------------------------------------- |
* + RTPRssmAdjustPacketParams() implementation |
* --------------------------------------------------------------------------- |
* |
* Adjust fields of the RTPRssmPacket to reflect the properties of its |
* payload. The payload format used by this reassembler defines a |
* fixed-length header that immediately precedes the audio data. Overriding |
* RTPRssmAdjustPacketParams() gives the reassembler a chance to update the |
* RTPRssmPacket data structure for each packet to reflect its payload header |
* length and audio data length. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_AdjustPacketParams( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
RTPRssmPacket * inPacket, |
SInt32 inFlags ) |
{ |
#pragma unused( inGlobals, inFlags ) |
UInt32 theHeaderSize; |
IMAAudioPayload * thePayload; |
theHeaderSize = sizeof( thePayload->itsFixedHeader ); |
inPacket->payloadHeaderLength = theHeaderSize; |
inPacket->dataLength -= theHeaderSize; |
return( noErr ); |
} |
/* --------------------------------------------------------------------------- |
* + RTPRssmCopyDataToChunk() implementation |
* --------------------------------------------------------------------------- |
* |
* Copy sample data from a packet list to the data buffer described by an |
* SHChunkRecord. The payloads processed by this reassembler indicate where |
* interleave audio data from each payload. This function iterates through |
* the packets, copying the data to the correct position in the chunk. The |
* function then calls __FillMissingData(), defined above, to synthesize lost |
* packet data. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_CopyDataToChunk( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
RTPRssmPacket * inPacketListHead, |
UInt32 inMaxChunkDataSize, |
SHChunkRecord * inChunk, |
SInt32 inFlags ) |
{ |
#pragma unused( inGlobals, inFlags ) |
ComponentResult theResult = noErr; |
UInt32 theFrameCount; |
IMAAudioFrame * theFrames; |
RTPRssmPacket * thePacket; |
const IMAAudioPayload * thePayload; |
UInt16 theGroupStartSequenceNumber; |
UInt32 theInterleaveCount; |
UInt32 theInterleaveIndex; |
UInt32 thePacketFrameCount; |
UInt32 theSourceIndex; |
UInt32 theTargetIndex; |
/* IMPORTANT The sequence number computations in this function work |
because the packets are in order and the separation |
between the packets is guaranteed to be within the |
precision of the RTP sequence number field (i.e., less |
than 16 bits, or 65536 packets). When computing with |
sequence numbers of packets that might be separated by |
more than 65535 packets, a reassembler must extend |
the precision of the sequence numbers, for instance by |
using the inNumWraparounds parameter of |
RTPRssmHandleNewPacket() or by using the timeStamp |
field of RTPRssmPacket structures. |
*/ |
inChunk->dataSize = __InterleaveGroupDataSize( inPacketListHead ); |
if( inChunk->dataSize > inMaxChunkDataSize ) |
{ |
/* this should never happen */ |
theResult = buffersTooSmall; |
} |
else |
{ |
theFrameCount = inChunk->dataSize / sizeof( IMAAudioFrame ); |
theFrames = |
REINTERPRET_CAST( IMAAudioFrame * )( |
CONST_CAST( UInt8 * )( inChunk->dataPtr ) ); |
thePayload = __GetPayload( inPacketListHead ); |
theInterleaveCount = IMAAudioPayloadInterleaveCount( thePayload ); |
theGroupStartSequenceNumber = |
inPacketListHead->sequenceNum - IMAAudioPayloadInterleaveIndex( thePayload ); |
for( thePacket = inPacketListHead; thePacket; thePacket = thePacket->next ) |
{ |
thePayload = __GetPayload( thePacket ); |
theInterleaveIndex = thePacket->sequenceNum - theGroupStartSequenceNumber; |
thePacketFrameCount = thePacket->dataLength / sizeof( IMAAudioFrame ); |
for( theSourceIndex = 0; theSourceIndex < thePacketFrameCount; theSourceIndex++ ) |
{ |
theTargetIndex = |
( theSourceIndex * theInterleaveCount ) + theInterleaveIndex; |
if( theTargetIndex < theFrameCount ) |
{ |
theFrames[ theTargetIndex ] = |
thePayload->itsAudioFrames[ theSourceIndex ]; |
} |
} |
} |
__FillMissingData( |
inPacketListHead, theGroupStartSequenceNumber, theInterleaveCount, inChunk ); |
} |
return( theResult ); |
} |
/* --------------------------------------------------------------------------- |
* + RTPRssmSendPacketList() implementation |
* --------------------------------------------------------------------------- |
* |
* Prepare to process or discard a list of packets. If the base detects that |
* some network packets were lost, overriding RTPRssmSendPacketList() gives |
* the reassembler a chance to decide whether it can handle the remaining |
* packets. This reassembler tolerates any amount of packet loss, so this |
* function simply clears the kRTPRssmLostSomePackets flag before delegating |
* to the base. When a reassembler is able to recover from packet loss, |
* turning off the kRTPRssmLostSomePackets flag before delegating the call to |
* the base reassembler prevents the base from discarding the packets. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_SendPacketList( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
RTPRssmPacket * inPacketListHead, |
const TimeValue64 * inLastChunkPresentationTime, |
SInt32 inFlags ) |
{ |
return( |
RTPRssmSendPacketList( |
( **inGlobals ).itsBase, inPacketListHead, inLastChunkPresentationTime, |
inFlags &= ~kRTPRssmLostSomePackets ) ); |
} |
/* --------------------------------------------------------------------------- |
* + RTPRssmHasCharacteristic() implementation |
* --------------------------------------------------------------------------- |
* |
* Indicate whether the reassembler has the specified characteristic. This |
* reassembler requires ordered packet lists. All other characteristics are |
* delegated to the base. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_HasCharacteristic( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
OSType inCharacteristic, |
Boolean * outHasIt ) |
{ |
ComponentResult theResult; |
if( inCharacteristic == kRTPRssmRequiresOrderedPacketsCharacteristic ) |
{ |
*outHasIt = true; |
theResult = noErr; |
} |
else |
{ |
theResult = |
RTPRssmHasCharacteristic( ( **inGlobals ).itsBase, inCharacteristic, outHasIt ); |
} |
return( theResult ); |
} |
/* --------------------------------------------------------------------------- |
* + RTPRssmReset() implementation |
* --------------------------------------------------------------------------- |
* |
* End processing of the current stream of network packets and prepare to |
* process a new, possibly unrelated, stream. This implementation simply |
* resets its base. |
* |
*/ |
EXTERN_API( ComponentResult ) |
RTPRssmIMAAudio_Reset( |
RTPRssmIMAAudioInstanceData ** inGlobals, |
SInt32 inFlags ) |
{ |
ComponentResult theResult; |
if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPRssmResetSelect ) ) |
theResult = RTPRssmReset( ( **inGlobals ).itsBase, inFlags ); |
else |
theResult = noErr; |
return( theResult ); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14