diff -r 48780e181b38 -r 578be2adaf3e Symbian3/PDK/Source/GUID-21E26B07-7E4D-50E0-97BE-C05CCD88B89F.dita --- a/Symbian3/PDK/Source/GUID-21E26B07-7E4D-50E0-97BE-C05CCD88B89F.dita Tue Jul 20 12:00:49 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-21E26B07-7E4D-50E0-97BE-C05CCD88B89F.dita Fri Aug 13 16:47:46 2010 +0100 @@ -1,180 +1,180 @@ - - - - - -Creating -a Sink Plugin -

A data sink plugin needs to implement the pure virtual (and where appropriate -override the virtual) base class mixin functions. This section describes how -to implement the MDataSink base class.

-

Note that it is possible for a single source/sink plugin to be both a source -and a sink, i.e. derive from both MDataSource and MDataSink.

-

See Creating a Source -Plugin for information on source/sink negotiation and data transfer.

- - -

Sink Plugin Instantiation

-

A client application instantiates a sink plugin using the RMMFController::AddDataSink() method, -passing in the UID of the sink as one of the parameters. The controller framework -instantiates a sink via the MDataSink::NewSinkL() method -rather than the more conventional NewL() method. This is -because, in some cases, a plugin can be both a sink and a sink of multimedia -data in which case the instantiation methods for sinks and sinks need to be -distinct. The MDataSink base class instantiation methods -are described below followed by how to write the instantiation methods in -the derived class.

-

The derived data sink needs to implement MDataSink::NewSinkL() and MDataSink::ConstructSinkL() for -instantiation. The constructor of a data sink plugin needs to specify what -type of data sink it is. This is achieved by passing a type UID into the MDataSink constructor.

-

If the sink has additional methods, that are not part of the base MDataSink class, -then a further layer of instantiation is required. For example, suppose CAcmeDataSink had -some extra methods that were not part of the base class then an additional -mxin interface for this class is required. For example:

-class MAcmeDataSink : public MDataSink - { -public: - inline static MAcmeDataSink* NewAcmeDataSinkL(TUid aImplemetationUid, const TDesC8& aInitData); - //This allows dynamic linkage to the Class: - } - -

The NewAcmeDataSinkL should be implemented as follows:

-MAcmeDataSink* retPtr = static_cast<MAcmeDataSink*>(MDataSink::NewSinkL(aImplementationUid, aInitData)); -

The class should derive from the MAcmeDataSink rather -than MDataSink as follows:

-class CAcmeDataSink: public CBase, public MAcmeDataSink - { -public: - MDataSink* NewSinkL(); - - - -

Sink Plugin Buffer Creation

-

Buffers are required to transfer data between a source and a sink. These -buffers may be created by the source and/or sink. The methods below are for -the sink buffer creation.

-

The MDataSink::CanCreateSinkBuffer() method must be -implemented by the data sink plugin. Most sinks should be capable of creating -their own buffer and so would return ETrue. Note that just -because a sink can create a buffer, this does not guarantee that the framework -will actually use the buffer created by the sink. Which buffer is used depends -on factors such as whether a null codec is used and whether the source is -the reference buffer, in either of these cases the sink buffer will not be -used.

-

The MDataSink::CreateSinkBufferL() method is called -by the framework to create a buffer from the sink. This method should create -a buffer of length 0 bytes and a maximum length of an appropriate size for -the sink. The meaning of 'appropriate' in this context depends on sink specifics, -such as whether the sink data ultimately comes from hardware that supplies -buffers of a certain size. Generally a larger buffer size means a smaller -number data transfers between the sink and sink are required. The returned -buffer must derive from CMMFBuffer but will be a derived -buffer eg CMMFDataBuffer or a video frame buffer.

-

The overloaded MDataSink::CreateSinkBufferL() method, -which has an additional aSinkBuffer parameter, is optional. -The default implementation is identical to the standard CreateSinkBufferL above. -This overloaded version is used where the nature of the sink buffer may impact -the created sink buffer. This method should only be overridden if the size -and/or type of the sink buffer can influence the size and/or type of the created -sink buffer.

- - -

Sink State Methods

-

The MDataSink mixin provides a number of state-related -functions used to inform a source/sink that the data path (via the controller) -has made a transition to a particular state. These state transition methods -are usually called on the source/sink from the datapath and so will be called -on the data source/sink plugin. These methods are not pure virtual and so -it is not compulsory to implement them.

-

The MDataSink::SinkThreadLogon() method indicates to -the sink that it can perform any thread specific initialisation. This is so -that the thread in which the data sink is instantiated is not necessarily -the same thread in which the actual transfer of data between the source and -the sink takes place. Any thread-specific sink initialisation cannot take -place in the NewSinkL() method and must instead be performed -in the MDataSink::SinkThreadLogon() method which is always -called in the thread in which the data transfer between sink and sink is to -take place.

-

The MAsyncEventHandler must also be passed into the -sink in the same thread in which the sink is to transfer data. If the sink -can generate events during a data transfer, then it must keep the reference -to event handler.

-

It is only necessary to provide an implementation of MDataSink::SinkThreadLogon() if -the sink has thread specific initialisation and/or can generate events during -data transfer.

-

Implementation of the MDataSink::SinkPrimeL(), MDataSink::SinkPlayL(), MDataSink::SinkPauseL() and MDataSink::SinkStopL() methods is optional. They -are called when a controller performs a transition to the corresponding state. -For example, if the controller starts, or resumes, playing then MDataSink::SinkPlayL() is -called.

-

Implementation of the MDataSink::SouceThreadLogoff() method -is optional. This method is called when the controller has finished with the -data sink and is called in the same thread as the data transfer. This allows -the data sink to perform any thread specific destruction such as the closure -of handles.

- - -

Sink Data Types

-

The MDataSink::SinkDataTypeCode() method must be implemented -by the data sink. It should return the data type of the sink for the specified -media ID. Some data sinks may need their data type to be explicitly set, via -the SetSinkDataTypeCode method or via negotiation with a -data sink, in which case this function should either return a default FourCC code, -or a NULL code, to indicate that the data type is not yet -known.

-

Implementation of the MDataSink::SetSinkDataTypeCode() method -is optional. It should be implemented where the sink can support multiple -data types.

- - -

Sink Custom Commands

-

The MDataSink::SinkCustomCommand() method facilitates -the use of custom commands. An example implementation is shown below:

-void CAcmeDataSink::SinkCustomCommand(TMMFMessage& aMessage) - { - // First, check we can handle message by checking its interface id - if (aMessage.InterfaceId() != KUidAcmeDatasinkCustomCommandInterface) - { - aMessage.Complete(KErrNotSupported); - return; - } - - // Next, dispatch the command to the appropriate method. - TInt error = KErrNone; - switch (aMessage.Function()) - { - case EAcmeDatasinkCustomCommandOne: - error = HandleCustomCommandOne(aMessage); - break; - case EAcmeDataSinkCustomCommandTwo: - error = HandleCustomCommandTwo(aMessage); - break; - default: - error = KErrNotSupported; - break; - } - aMessage.Complete(error); - } - -

Use of the custom command mechanism is preferable to adding extra methods -as it avoids extra casting.

- - -

Sink Priority Settings

-

The MDataSink::SetSinkPrioritySettings() method is optional. -It is used to provide a mechanism to determine which sink should have priority -in cases where more than one client wishes to use the same physical sink. -An example might be an audio output, although several audio output sinks can -be created, the actual hardware may only have one physical speaker. Therefore, -if one audio output is being used to play music, and another is being used -to play a ring tone due to an incoming call, then the latter needs to take -precedence. TMMFPrioritySettings contains an iPriority -TInt data member, where 100 is maximum priority, 0 is normal and --100 is minimum priority. The TMMFPrioritySettings::TMdaPriorityPreference and TMMFPrioritySettings::TMMFStateA data members provide further information which may be used if required. -These specify whether the priority applies to recording or playing.

+ + + + + +Creating +a Sink Plugin +

A data sink plugin needs to implement the pure virtual (and where appropriate +override the virtual) base class mixin functions. This section describes how +to implement the MDataSink base class.

+

Note that it is possible for a single source/sink plugin to be both a source +and a sink, i.e. derive from both MDataSource and MDataSink.

+

See Creating a Source +Plugin for information on source/sink negotiation and data transfer.

+ + +

Sink Plugin Instantiation

+

A client application instantiates a sink plugin using the RMMFController::AddDataSink() method, +passing in the UID of the sink as one of the parameters. The controller framework +instantiates a sink via the MDataSink::NewSinkL() method +rather than the more conventional NewL() method. This is +because, in some cases, a plugin can be both a sink and a sink of multimedia +data in which case the instantiation methods for sinks and sinks need to be +distinct. The MDataSink base class instantiation methods +are described below followed by how to write the instantiation methods in +the derived class.

+

The derived data sink needs to implement MDataSink::NewSinkL() and MDataSink::ConstructSinkL() for +instantiation. The constructor of a data sink plugin needs to specify what +type of data sink it is. This is achieved by passing a type UID into the MDataSink constructor.

+

If the sink has additional methods, that are not part of the base MDataSink class, +then a further layer of instantiation is required. For example, suppose CAcmeDataSink had +some extra methods that were not part of the base class then an additional +mxin interface for this class is required. For example:

+class MAcmeDataSink : public MDataSink + { +public: + inline static MAcmeDataSink* NewAcmeDataSinkL(TUid aImplemetationUid, const TDesC8& aInitData); + //This allows dynamic linkage to the Class: + } + +

The NewAcmeDataSinkL should be implemented as follows:

+MAcmeDataSink* retPtr = static_cast<MAcmeDataSink*>(MDataSink::NewSinkL(aImplementationUid, aInitData)); +

The class should derive from the MAcmeDataSink rather +than MDataSink as follows:

+class CAcmeDataSink: public CBase, public MAcmeDataSink + { +public: + MDataSink* NewSinkL(); + + + +

Sink Plugin Buffer Creation

+

Buffers are required to transfer data between a source and a sink. These +buffers may be created by the source and/or sink. The methods below are for +the sink buffer creation.

+

The MDataSink::CanCreateSinkBuffer() method must be +implemented by the data sink plugin. Most sinks should be capable of creating +their own buffer and so would return ETrue. Note that just +because a sink can create a buffer, this does not guarantee that the framework +will actually use the buffer created by the sink. Which buffer is used depends +on factors such as whether a null codec is used and whether the source is +the reference buffer, in either of these cases the sink buffer will not be +used.

+

The MDataSink::CreateSinkBufferL() method is called +by the framework to create a buffer from the sink. This method should create +a buffer of length 0 bytes and a maximum length of an appropriate size for +the sink. The meaning of 'appropriate' in this context depends on sink specifics, +such as whether the sink data ultimately comes from hardware that supplies +buffers of a certain size. Generally a larger buffer size means a smaller +number data transfers between the sink and sink are required. The returned +buffer must derive from CMMFBuffer but will be a derived +buffer eg CMMFDataBuffer or a video frame buffer.

+

The overloaded MDataSink::CreateSinkBufferL() method, +which has an additional aSinkBuffer parameter, is optional. +The default implementation is identical to the standard CreateSinkBufferL above. +This overloaded version is used where the nature of the sink buffer may impact +the created sink buffer. This method should only be overridden if the size +and/or type of the sink buffer can influence the size and/or type of the created +sink buffer.

+ + +

Sink State Methods

+

The MDataSink mixin provides a number of state-related +functions used to inform a source/sink that the data path (via the controller) +has made a transition to a particular state. These state transition methods +are usually called on the source/sink from the datapath and so will be called +on the data source/sink plugin. These methods are not pure virtual and so +it is not compulsory to implement them.

+

The MDataSink::SinkThreadLogon() method indicates to +the sink that it can perform any thread specific initialisation. This is so +that the thread in which the data sink is instantiated is not necessarily +the same thread in which the actual transfer of data between the source and +the sink takes place. Any thread-specific sink initialisation cannot take +place in the NewSinkL() method and must instead be performed +in the MDataSink::SinkThreadLogon() method which is always +called in the thread in which the data transfer between sink and sink is to +take place.

+

The MAsyncEventHandler must also be passed into the +sink in the same thread in which the sink is to transfer data. If the sink +can generate events during a data transfer, then it must keep the reference +to event handler.

+

It is only necessary to provide an implementation of MDataSink::SinkThreadLogon() if +the sink has thread specific initialisation and/or can generate events during +data transfer.

+

Implementation of the MDataSink::SinkPrimeL(), MDataSink::SinkPlayL(), MDataSink::SinkPauseL() and MDataSink::SinkStopL() methods is optional. They +are called when a controller performs a transition to the corresponding state. +For example, if the controller starts, or resumes, playing then MDataSink::SinkPlayL() is +called.

+

Implementation of the MDataSink::SouceThreadLogoff() method +is optional. This method is called when the controller has finished with the +data sink and is called in the same thread as the data transfer. This allows +the data sink to perform any thread specific destruction such as the closure +of handles.

+ + +

Sink Data Types

+

The MDataSink::SinkDataTypeCode() method must be implemented +by the data sink. It should return the data type of the sink for the specified +media ID. Some data sinks may need their data type to be explicitly set, via +the SetSinkDataTypeCode method or via negotiation with a +data sink, in which case this function should either return a default FourCC code, +or a NULL code, to indicate that the data type is not yet +known.

+

Implementation of the MDataSink::SetSinkDataTypeCode() method +is optional. It should be implemented where the sink can support multiple +data types.

+ + +

Sink Custom Commands

+

The MDataSink::SinkCustomCommand() method facilitates +the use of custom commands. An example implementation is shown below:

+void CAcmeDataSink::SinkCustomCommand(TMMFMessage& aMessage) + { + // First, check we can handle message by checking its interface id + if (aMessage.InterfaceId() != KUidAcmeDatasinkCustomCommandInterface) + { + aMessage.Complete(KErrNotSupported); + return; + } + + // Next, dispatch the command to the appropriate method. + TInt error = KErrNone; + switch (aMessage.Function()) + { + case EAcmeDatasinkCustomCommandOne: + error = HandleCustomCommandOne(aMessage); + break; + case EAcmeDataSinkCustomCommandTwo: + error = HandleCustomCommandTwo(aMessage); + break; + default: + error = KErrNotSupported; + break; + } + aMessage.Complete(error); + } + +

Use of the custom command mechanism is preferable to adding extra methods +as it avoids extra casting.

+ + +

Sink Priority Settings

+

The MDataSink::SetSinkPrioritySettings() method is optional. +It is used to provide a mechanism to determine which sink should have priority +in cases where more than one client wishes to use the same physical sink. +An example might be an audio output, although several audio output sinks can +be created, the actual hardware may only have one physical speaker. Therefore, +if one audio output is being used to play music, and another is being used +to play a ring tone due to an incoming call, then the latter needs to take +precedence. TMMFPrioritySettings contains an iPriority +TInt data member, where 100 is maximum priority, 0 is normal and +-100 is minimum priority. The TMMFPrioritySettings::TMdaPriorityPreference and TMMFPrioritySettings::TMMFStateA data members provide further information which may be used if required. +These specify whether the priority applies to recording or playing.

\ No newline at end of file