Symbian3/PDK/Source/GUID-21E26B07-7E4D-50E0-97BE-C05CCD88B89F.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Fri, 13 Aug 2010 16:47:46 +0100
changeset 14 578be2adaf3e
parent 5 f345bda72bc4
permissions -rw-r--r--
Week 32 contribution of PDK documentation content. See release notes for details. Fixes bug Bug 3582

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-21E26B07-7E4D-50E0-97BE-C05CCD88B89F" xml:lang="en"><title>Creating
a Sink Plugin</title><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>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 <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> base class.</p>
<p>Note that it is possible for a single source/sink plugin to be both a source
and a sink, i.e. derive from both <xref href="GUID-2230F976-A798-30EB-ABA6-09C86716A4B5.dita"><apiname>MDataSource</apiname></xref> and <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref>. </p>
<p>See <xref href="GUID-B998B8FC-3DC3-57B5-A4E6-C4D903B4ACF9.dita">Creating a Source
Plugin</xref> for information on source/sink negotiation and data transfer.</p>


<p><b> Sink Plugin Instantiation</b> </p>
<p>A client application instantiates a sink plugin using the <xref href="GUID-9DEDFB0F-C963-3FB7-9237-DDDB276C8841.dita#GUID-9DEDFB0F-C963-3FB7-9237-DDDB276C8841/GUID-2D177C9B-51F7-30EE-862E-F282E28B3633"><apiname>RMMFController::AddDataSink()</apiname></xref> method,
passing in the UID of the sink as one of the parameters. The controller framework
instantiates a sink via the <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-04B8016D-E8A3-3F00-8367-6D20C407A240"><apiname>MDataSink::NewSinkL()</apiname></xref> method
rather than the more conventional <codeph>NewL()</codeph> 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 <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> base class instantiation methods
are described below followed by how to write the instantiation methods in
the derived class. </p>
<p>The derived data sink needs to implement <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-04B8016D-E8A3-3F00-8367-6D20C407A240"><apiname>MDataSink::NewSinkL()</apiname></xref> and <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-AEC3FEB6-ED46-3E73-85D6-FD298CE1DE6C"><apiname>MDataSink::ConstructSinkL()</apiname></xref> 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 <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> constructor. </p>
<p>If the sink has additional methods, that are not part of the base <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> class,
then a further layer of instantiation is required. For example, suppose <codeph>CAcmeDataSink</codeph> had
some extra methods that were not part of the base class then an additional
mxin interface for this class is required. For example:</p>
<codeblock id="GUID-D81EF01A-7C6C-5EBF-BCC9-3A45378C0466" xml:space="preserve">class MAcmeDataSink : public MDataSink
    {
public:
    inline static MAcmeDataSink* NewAcmeDataSinkL(TUid aImplemetationUid, const TDesC8&amp; aInitData);
    //This allows dynamic linkage to the Class:
    }
</codeblock>
<p>The <codeph>NewAcmeDataSinkL</codeph> should be implemented as follows:</p>
<codeblock id="GUID-CDA802E2-20C6-5FEF-9429-0ED3B45322C8" xml:space="preserve">MAcmeDataSink* retPtr = static_cast&lt;MAcmeDataSink*&gt;(MDataSink::NewSinkL(aImplementationUid, aInitData));</codeblock>
<p>The class should derive from the <codeph>MAcmeDataSink</codeph> rather
than <codeph>MDataSink</codeph> as follows:</p>
<codeblock id="GUID-C06D0D2C-C24A-59B6-9775-0521509C8F5B" xml:space="preserve">class CAcmeDataSink: public CBase, public MAcmeDataSink
    {
public:
 MDataSink* NewSinkL();
</codeblock>


<p><b>Sink Plugin Buffer Creation</b> </p>
<p>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.</p>
<p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-774C8837-30F7-39C5-ACC9-0AEC1757070C"><apiname>MDataSink::CanCreateSinkBuffer()</apiname></xref> method must be
implemented by the data sink plugin. Most sinks should be capable of creating
their own buffer and so would return <codeph>ETrue</codeph>. 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.</p>
<p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-8D998E91-9AF2-3734-A11A-985BD15E324C"><apiname>MDataSink::CreateSinkBufferL()</apiname></xref> 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 <xref href="GUID-9A7A83ED-592B-3A0C-BABB-3B90099BCF7C.dita"><apiname>CMMFBuffer</apiname></xref> but will be a derived
buffer eg <xref href="GUID-AE26E6A4-C1AD-3B35-B5F7-CE0AB60169BB.dita"><apiname>CMMFDataBuffer</apiname></xref> or a video frame buffer.</p>
<p>The overloaded <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-8D998E91-9AF2-3734-A11A-985BD15E324C"><apiname>MDataSink::CreateSinkBufferL()</apiname></xref> method,
which has an additional <codeph>aSinkBuffer</codeph> parameter, is optional.
The default implementation is identical to the standard <codeph>CreateSinkBufferL</codeph> 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.</p>


<p><b>Sink State Methods</b> </p>
<p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> 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. </p>
<p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-A6CD1868-BAF7-332E-8C35-BE3F494E3D2D"><apiname>MDataSink::SinkThreadLogon()</apiname></xref> 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 <codeph>NewSinkL()</codeph> method and must instead be performed
in the <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-A6CD1868-BAF7-332E-8C35-BE3F494E3D2D"><apiname>MDataSink::SinkThreadLogon()</apiname></xref> method which is always
called in the thread in which the data transfer between sink and sink is to
take place.</p>
<p>The <xref href="GUID-8512F793-107A-3166-A62F-750696D942CE.dita"><apiname>MAsyncEventHandler</apiname></xref> 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.</p>
<p>It is only necessary to provide an implementation of <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-A6CD1868-BAF7-332E-8C35-BE3F494E3D2D"><apiname>MDataSink::SinkThreadLogon()</apiname></xref> if
the sink has thread specific initialisation and/or can generate events during
data transfer.</p>
<p>Implementation of the <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-17E785C1-D177-317F-82D1-D9727CE56399"><apiname>MDataSink::SinkPrimeL()</apiname></xref>, <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-63057BF2-4730-3042-AA32-1D06F455AE17"><apiname>MDataSink::SinkPlayL()</apiname></xref>, <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-5E0447D4-A48D-35B3-AEDF-758EB249FAE2"><apiname>MDataSink::SinkPauseL()</apiname></xref> and <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-E8627DBE-5709-388E-ABB1-0FC2DB8683D2"><apiname>MDataSink::SinkStopL()</apiname></xref> 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 <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-63057BF2-4730-3042-AA32-1D06F455AE17"><apiname>MDataSink::SinkPlayL()</apiname></xref> is
called.</p>
<p>Implementation of the <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-67D5D509-E5C1-3A93-B4E8-E6083E16E7A5"><apiname>MDataSink::SouceThreadLogoff()</apiname></xref> 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. </p>


<p><b>Sink Data Types</b> </p>
<p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-04666F46-042D-311C-828D-A85B65DE992E"><apiname>MDataSink::SinkDataTypeCode()</apiname></xref> 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 <codeph>SetSinkDataTypeCode</codeph> method or via negotiation with a
data sink, in which case this function should either return a default <codeph>FourCC</codeph> code,
or a <codeph>NULL</codeph> code, to indicate that the data type is not yet
known.</p>
<p>Implementation of the <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-BB031D9F-2345-3519-88D0-D6EE0CBFEE57"><apiname>MDataSink::SetSinkDataTypeCode()</apiname></xref> method
is optional. It should be implemented where the sink can support multiple
data types.</p>


<p><b>Sink Custom Commands</b> </p>
<p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-EBF981DD-9C18-3417-BAC6-57DA837D4CEA"><apiname>MDataSink::SinkCustomCommand()</apiname></xref> method facilitates
the use of custom commands. An example implementation is shown below:</p>
<codeblock id="GUID-C04BBBD3-9991-5478-9920-E7FFE28DB166" xml:space="preserve">void CAcmeDataSink::SinkCustomCommand(TMMFMessage&amp; 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);
    }
</codeblock>
<p>Use of the custom command mechanism is preferable to adding extra methods
as it avoids extra casting.</p>


<p><b>Sink Priority Settings</b> </p>
<p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-B045F6E3-7D43-3EB0-8AA7-1DF58AC7AFF5"><apiname>MDataSink::SetSinkPrioritySettings()</apiname></xref> 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. <xref href="GUID-AA73C7C3-5874-34D1-8879-597B0900E9F3.dita"><apiname>TMMFPrioritySettings</apiname></xref> contains an <codeph>iPriority
TInt</codeph> data member, where 100 is maximum priority, 0 is normal and
-100 is minimum priority. The <xref href="GUID-AA73C7C3-5874-34D1-8879-597B0900E9F3.dita#GUID-AA73C7C3-5874-34D1-8879-597B0900E9F3/GUID-3B14D763-139C-3A4E-9640-CABBC3427D6E"><apiname>TMMFPrioritySettings::TMdaPriorityPreference</apiname></xref> and <xref href="GUID-AA73C7C3-5874-34D1-8879-597B0900E9F3.dita#GUID-AA73C7C3-5874-34D1-8879-597B0900E9F3/GUID-A2E1FCFD-2058-3E1D-9FEF-C562F613C65D"><apiname>TMMFPrioritySettings::TMMFStateA</apiname></xref> data members provide further information which may be used if required.
These specify whether the priority applies to recording or playing.</p>
</conbody></concept>