|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-21E26B07-7E4D-50E0-97BE-C05CCD88B89F" xml:lang="en"><title>Creating |
|
13 a Sink Plugin</title><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <p>A data sink plugin needs to implement the pure virtual (and where appropriate |
|
15 override the virtual) base class mixin functions. This section describes how |
|
16 to implement the <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> base class.</p> |
|
17 <p>Note that it is possible for a single source/sink plugin to be both a source |
|
18 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> |
|
19 <p>See <xref href="GUID-B998B8FC-3DC3-57B5-A4E6-C4D903B4ACF9.dita">Creating a Source |
|
20 Plugin</xref> for information on source/sink negotiation and data transfer.</p> |
|
21 |
|
22 |
|
23 <p><b> Sink Plugin Instantiation</b> </p> |
|
24 <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, |
|
25 passing in the UID of the sink as one of the parameters. The controller framework |
|
26 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 |
|
27 rather than the more conventional <codeph>NewL()</codeph> method. This is |
|
28 because, in some cases, a plugin can be both a sink and a sink of multimedia |
|
29 data in which case the instantiation methods for sinks and sinks need to be |
|
30 distinct. The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> base class instantiation methods |
|
31 are described below followed by how to write the instantiation methods in |
|
32 the derived class. </p> |
|
33 <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 |
|
34 instantiation. The constructor of a data sink plugin needs to specify what |
|
35 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> |
|
36 <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, |
|
37 then a further layer of instantiation is required. For example, suppose <codeph>CAcmeDataSink</codeph> had |
|
38 some extra methods that were not part of the base class then an additional |
|
39 mxin interface for this class is required. For example:</p> |
|
40 <codeblock id="GUID-D81EF01A-7C6C-5EBF-BCC9-3A45378C0466" xml:space="preserve">class MAcmeDataSink : public MDataSink |
|
41 { |
|
42 public: |
|
43 inline static MAcmeDataSink* NewAcmeDataSinkL(TUid aImplemetationUid, const TDesC8& aInitData); |
|
44 //This allows dynamic linkage to the Class: |
|
45 } |
|
46 </codeblock> |
|
47 <p>The <codeph>NewAcmeDataSinkL</codeph> should be implemented as follows:</p> |
|
48 <codeblock id="GUID-CDA802E2-20C6-5FEF-9429-0ED3B45322C8" xml:space="preserve">MAcmeDataSink* retPtr = static_cast<MAcmeDataSink*>(MDataSink::NewSinkL(aImplementationUid, aInitData));</codeblock> |
|
49 <p>The class should derive from the <codeph>MAcmeDataSink</codeph> rather |
|
50 than <codeph>MDataSink</codeph> as follows:</p> |
|
51 <codeblock id="GUID-C06D0D2C-C24A-59B6-9775-0521509C8F5B" xml:space="preserve">class CAcmeDataSink: public CBase, public MAcmeDataSink |
|
52 { |
|
53 public: |
|
54 MDataSink* NewSinkL(); |
|
55 </codeblock> |
|
56 |
|
57 |
|
58 <p><b>Sink Plugin Buffer Creation</b> </p> |
|
59 <p>Buffers are required to transfer data between a source and a sink. These |
|
60 buffers may be created by the source and/or sink. The methods below are for |
|
61 the sink buffer creation.</p> |
|
62 <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 |
|
63 implemented by the data sink plugin. Most sinks should be capable of creating |
|
64 their own buffer and so would return <codeph>ETrue</codeph>. Note that just |
|
65 because a sink can create a buffer, this does not guarantee that the framework |
|
66 will actually use the buffer created by the sink. Which buffer is used depends |
|
67 on factors such as whether a null codec is used and whether the source is |
|
68 the reference buffer, in either of these cases the sink buffer will not be |
|
69 used.</p> |
|
70 <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 |
|
71 by the framework to create a buffer from the sink. This method should create |
|
72 a buffer of length 0 bytes and a maximum length of an appropriate size for |
|
73 the sink. The meaning of 'appropriate' in this context depends on sink specifics, |
|
74 such as whether the sink data ultimately comes from hardware that supplies |
|
75 buffers of a certain size. Generally a larger buffer size means a smaller |
|
76 number data transfers between the sink and sink are required. The returned |
|
77 buffer must derive from <xref href="GUID-9A7A83ED-592B-3A0C-BABB-3B90099BCF7C.dita"><apiname>CMMFBuffer</apiname></xref> but will be a derived |
|
78 buffer eg <xref href="GUID-AE26E6A4-C1AD-3B35-B5F7-CE0AB60169BB.dita"><apiname>CMMFDataBuffer</apiname></xref> or a video frame buffer.</p> |
|
79 <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, |
|
80 which has an additional <codeph>aSinkBuffer</codeph> parameter, is optional. |
|
81 The default implementation is identical to the standard <codeph>CreateSinkBufferL</codeph> above. |
|
82 This overloaded version is used where the nature of the sink buffer may impact |
|
83 the created sink buffer. This method should only be overridden if the size |
|
84 and/or type of the sink buffer can influence the size and/or type of the created |
|
85 sink buffer.</p> |
|
86 |
|
87 |
|
88 <p><b>Sink State Methods</b> </p> |
|
89 <p>The <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> mixin provides a number of state-related |
|
90 functions used to inform a source/sink that the data path (via the controller) |
|
91 has made a transition to a particular state. These state transition methods |
|
92 are usually called on the source/sink from the datapath and so will be called |
|
93 on the data source/sink plugin. These methods are not pure virtual and so |
|
94 it is not compulsory to implement them. </p> |
|
95 <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 |
|
96 the sink that it can perform any thread specific initialisation. This is so |
|
97 that the thread in which the data sink is instantiated is not necessarily |
|
98 the same thread in which the actual transfer of data between the source and |
|
99 the sink takes place. Any thread-specific sink initialisation cannot take |
|
100 place in the <codeph>NewSinkL()</codeph> method and must instead be performed |
|
101 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 |
|
102 called in the thread in which the data transfer between sink and sink is to |
|
103 take place.</p> |
|
104 <p>The <xref href="GUID-8512F793-107A-3166-A62F-750696D942CE.dita"><apiname>MAsyncEventHandler</apiname></xref> must also be passed into the |
|
105 sink in the same thread in which the sink is to transfer data. If the sink |
|
106 can generate events during a data transfer, then it must keep the reference |
|
107 to event handler.</p> |
|
108 <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 |
|
109 the sink has thread specific initialisation and/or can generate events during |
|
110 data transfer.</p> |
|
111 <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 |
|
112 are called when a controller performs a transition to the corresponding state. |
|
113 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 |
|
114 called.</p> |
|
115 <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 |
|
116 is optional. This method is called when the controller has finished with the |
|
117 data sink and is called in the same thread as the data transfer. This allows |
|
118 the data sink to perform any thread specific destruction such as the closure |
|
119 of handles. </p> |
|
120 |
|
121 |
|
122 <p><b>Sink Data Types</b> </p> |
|
123 <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 |
|
124 by the data sink. It should return the data type of the sink for the specified |
|
125 media ID. Some data sinks may need their data type to be explicitly set, via |
|
126 the <codeph>SetSinkDataTypeCode</codeph> method or via negotiation with a |
|
127 data sink, in which case this function should either return a default <codeph>FourCC</codeph> code, |
|
128 or a <codeph>NULL</codeph> code, to indicate that the data type is not yet |
|
129 known.</p> |
|
130 <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 |
|
131 is optional. It should be implemented where the sink can support multiple |
|
132 data types.</p> |
|
133 |
|
134 |
|
135 <p><b>Sink Custom Commands</b> </p> |
|
136 <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 |
|
137 the use of custom commands. An example implementation is shown below:</p> |
|
138 <codeblock id="GUID-C04BBBD3-9991-5478-9920-E7FFE28DB166" xml:space="preserve">void CAcmeDataSink::SinkCustomCommand(TMMFMessage& aMessage) |
|
139 { |
|
140 // First, check we can handle message by checking its interface id |
|
141 if (aMessage.InterfaceId() != KUidAcmeDatasinkCustomCommandInterface) |
|
142 { |
|
143 aMessage.Complete(KErrNotSupported); |
|
144 return; |
|
145 } |
|
146 |
|
147 // Next, dispatch the command to the appropriate method. |
|
148 TInt error = KErrNone; |
|
149 switch (aMessage.Function()) |
|
150 { |
|
151 case EAcmeDatasinkCustomCommandOne: |
|
152 error = HandleCustomCommandOne(aMessage); |
|
153 break; |
|
154 case EAcmeDataSinkCustomCommandTwo: |
|
155 error = HandleCustomCommandTwo(aMessage); |
|
156 break; |
|
157 default: |
|
158 error = KErrNotSupported; |
|
159 break; |
|
160 } |
|
161 aMessage.Complete(error); |
|
162 } |
|
163 </codeblock> |
|
164 <p>Use of the custom command mechanism is preferable to adding extra methods |
|
165 as it avoids extra casting.</p> |
|
166 |
|
167 |
|
168 <p><b>Sink Priority Settings</b> </p> |
|
169 <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. |
|
170 It is used to provide a mechanism to determine which sink should have priority |
|
171 in cases where more than one client wishes to use the same physical sink. |
|
172 An example might be an audio output, although several audio output sinks can |
|
173 be created, the actual hardware may only have one physical speaker. Therefore, |
|
174 if one audio output is being used to play music, and another is being used |
|
175 to play a ring tone due to an incoming call, then the latter needs to take |
|
176 precedence. <xref href="GUID-AA73C7C3-5874-34D1-8879-597B0900E9F3.dita"><apiname>TMMFPrioritySettings</apiname></xref> contains an <codeph>iPriority |
|
177 TInt</codeph> data member, where 100 is maximum priority, 0 is normal and |
|
178 -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. |
|
179 These specify whether the priority applies to recording or playing.</p> |
|
180 </conbody></concept> |