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-528BDE53-327A-5D34-B4BF-CB2421BE43C8" xml:lang="en"><title>Writinga controller plugin</title><prolog><metadata><keywords/></metadata></prolog><conbody><p>This document explains how to write a controller plugin. </p><section id="GUID-215B50CF-605A-58BA-8E87-CAB942F11741"><title>Purpose</title> <p>Acontroller plugin is the main type of multimedia framework (MMF) plugin. Acontroller plugin typically supports playing or recording one or more multimediaformats, <codeph>mp3</codeph> or <codeph>avi</codeph> for example. A controllerplugin is able to read data from one or more sources, apply any required datatransformations and write the data to the appropriate sink. </p> <p><b>RequiredBackground</b> </p> <p>You need to be familiar with the Symbian platform PluginFramework. </p> </section><section id="GUID-0DB9E8B5-8B2A-4EB3-998F-376762CAC3D5"><title>Using the ControllerPlugin </title> <p>The following tasks will be covered in this tutorial: </p> <ul><li id="GUID-BDA97F96-C90A-5F4E-BEBE-93478FB24453"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-3C8AEA0B-5FE3-5691-B108-05C87F229D07">Implementing the core controller plugin interface</xref> </p> </li><li id="GUID-501F72DA-77B8-5FC8-81AB-CCDE9490DF2D"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-C5696F98-4ECF-5086-AC1A-BF17BCFECC29">Implementing the standard custom command interfaces</xref> </p> </li><li id="GUID-94D36263-EC2D-5145-9D22-F0C1BDDB209B"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-A305F052-58F4-57B9-AB0F-C172768E462F">Interaction with MMF Base Classes and other plugins</xref> </p> </li><li id="GUID-9A37DC2C-2E8D-55FC-9C85-A34008FC4F9C"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-9FD6AAA8-4024-578F-9AB4-48F7017D3EB6">Integrating the controller into the ECom plugin framework</xref> </p> </li><li id="GUID-B53B937C-2D8A-5311-92E2-6458B0CEF2B0"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-0F96339A-BF77-570C-908D-A59AFD2036DB">Testing</xref> </p> </li></ul> <p><b>BasicProcedure</b> </p> <p>The basic steps for writing a controller plugin areshown here: </p> <ol id="GUID-D235DD92-682F-542D-AE6D-0EF5B7199E10"><li id="GUID-5806F6ED-FBDA-5BCC-80C8-C70DEBDAB3A9"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-3C8AEA0B-5FE3-5691-B108-05C87F229D07">Implementing the core controller plugin interface</xref> </p> </li><li id="GUID-00D29242-1610-5ACD-9E97-C87945CF7D4C"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-C5696F98-4ECF-5086-AC1A-BF17BCFECC29">Implementing the standard custom command interfaces</xref> </p> </li><li id="GUID-B925D042-C292-51B4-8490-5D4DD769A307"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-A305F052-58F4-57B9-AB0F-C172768E462F">Interaction with MMF Base Classes and other plugins</xref> </p> </li><li id="GUID-4F7B6585-23AC-5C0E-9BB6-9354C41BD27A"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-9FD6AAA8-4024-578F-9AB4-48F7017D3EB6">Integrating the controller into the ECom plugin framework</xref> </p> </li><li id="GUID-6F8A6A17-29BC-5268-95D9-FACB91622C3E"><p><xref href="GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8.dita#GUID-528BDE53-327A-5D34-B4BF-CB2421BE43C8/GUID-0F96339A-BF77-570C-908D-A59AFD2036DB">Testing</xref> </p> </li></ol> </section><section id="GUID-3C8AEA0B-5FE3-5691-B108-05C87F229D07"><title>Implementingthe core controller plugin interface</title> <p>The controller plugin APIis defined by the controller framework element of the MMF. All controllerplugin implementations must derive from the abstract class <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita"><apiname>CMMFController</apiname></xref> andimplement its pure virtual methods. </p> <p>As well as providing the controllerAPI, the <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita"><apiname>CMMFController</apiname></xref> base class also provides functionalitysuch as instantiation of controller plugins via the <xref href="GUID-9E92EE30-F2E2-5F28-BB2A-391C09EC69D2.dita">ECom</xref> pluginframework, inter-thread message decoding and parameter unpacking, an objectreference counting mechanism and a few utility methods for use by controllerplugins. </p> <p>The following sections describe how to implement the controllerAPI. </p> <p><b>Sources and sinks </b> </p> <p>Sources and sinks are themselves <xref href="GUID-9E92EE30-F2E2-5F28-BB2A-391C09EC69D2.dita">ECom</xref> plugins and providean interface that allows the controller to read and write raw data buffers.The type of source or sink, along with any source- specific or sink-specificinitialisation parameters (for example, the file name for a file source),is specified by the client. The source or sink is then created and owned bythe controller framework. It is then passed into the controller plugin viaa call to <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-11623B04-A83E-3E32-A06E-6454D8407ADB"><apiname>CMMFController::AddDataSourceL()</apiname></xref> or <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-8842FF05-7822-317A-A650-225775B758FD"><apiname>CMMFController::AddDataSinkL()</apiname></xref> fora data source or a data sink respectively. </p> <p> <b> Note :</b> The ownershipof a source or sink always remains with the controller framework and not withthe controller plugin, and that a controller plugin should never delete asource or sink. If the controller plugin leaves during the call to <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-11623B04-A83E-3E32-A06E-6454D8407ADB"><apiname>CMMFController::AddDataSourceL()</apiname></xref> or <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-8842FF05-7822-317A-A650-225775B758FD"><apiname>CMMFController::AddDataSinkL()</apiname></xref>, the source or sink will be destroyed by the controller framework. </p> <p>Thereis no limit on the number of sources or sinks that can be added to a particularcontroller plugin, other than the limit provided by the plugin itself. Forexample, an audio controller would have one source and one sink. A video playingcontroller would have one source and two sinks (display and speaker). </p> <p>Sourcesand sinks can also be removed from the controller plugin by the client. Thereference of the particular source or sink being removed is passed into eitherthe <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-6CA27841-ACBE-303B-84A6-225F77B6CC53"><apiname>CMMFController::RemoveDataSourceL()</apiname></xref> or <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-FD6A61E9-B355-36BA-9FF5-AA5E694F76FA"><apiname>CMMFController::RemoveDataSinkL()</apiname></xref> methodto remove a data source or a data sink respectively. The controller pluginshould remove any reference that it has to the source or sink; the sourceor sink will then be deleted by the controller framework. </p> <p> <b>Note:</b> Ifthe controller plugin leaves during these calls (for example, if it does notsupport the removal of sources or sinks), the controller framework will notdelete the source or sink. </p> <p><b>Controller states </b> </p> <p>The Controller plugin states, along withthe commands to transition the plugin between the states, are: </p> <ul><li id="GUID-15FEBAAD-0C40-5029-B8ED-080967BD5980"><p> <codeph>Open</codeph>,this is the current state of the controller, after it has been created. Oncethe controller has been configured, it moves to the <codeph>Stopped</codeph> state.This transition typically involves adding the source(s) and sink(s) and configuringany utility objects or other plugins owned by the controller. </p> </li><li id="GUID-4BD7C0FB-AB98-5373-B7A8-BFCF8E6ECC76"><p> <codeph>Stopped</codeph>,in this state the controller should not have any resources or buffers allocated,and the position should be zero. </p> </li><li id="GUID-BBDACB71-F927-5AB0-B6CA-838DB6B48422"><p> <codeph>Primed</codeph>,in moving to the primed state, the controller should allocate any buffersand resources that will be required to perform playback. The playback or recordingposition should also be stored when the controllere is in the <codeph>primed</codeph> state.Controllers should only be moved into this state just before play, otherwiseunnecessary memory and resources will be used. </p> </li><li id="GUID-8D3C5466-1A8E-5F0B-9607-AFE4CF651D23"><p> <codeph>Playing</codeph>,when in this state, the controller plugin should be transferring data betweensource(s) and sink(s). </p> </li></ul> <p>Calling <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-AA743B27-C597-3D6A-B10C-C51224EC78FA"><apiname>CMMFController::ResetL()</apiname></xref> on the controllerplugin should cause it to revert back to the <codeph>Open</codeph> state.This will involve stopping playback, deleting any allocated resources, andremoving any references to sources and sinks. </p> <p><b>Position and Duration </b> </p> <p>Position and duration can be set byderiving from the pure virtual methods <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-01BBB3DC-0178-392C-9A8C-F2B8A563FC1B"><apiname>CMMFController::PositionL()</apiname></xref>, <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-8DA4E77A-07EF-304B-9AA6-0A744C6CD3B4"><apiname>CMMFController::SetPositionL()</apiname></xref> and <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-D61C8034-587A-3FEC-9659-155E547F9042"><apiname>CMMFController::DurationL()</apiname></xref>. </p> <p> <codeph>Note:</codeph> The <i>position</i> hasmeaning only in the <codeph>Primed</codeph> and <codeph>Playing</codeph> states.The controller plugin should leave with <codeph>KErrNotReady</codeph> if anattempt is made to set or get the position when the controller is in any otherstate. However, it should be possible to query the duration as soon as thedata source or data sink has been added. </p> <p><b>Custom Commands </b> </p> <p>Custom commands allow controller plugin writersto extend the basic controller API. They sends messages from the client throughthe controller framework to the controller plugin. </p> <p>The <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-C3ADC1F7-97DB-3324-9C3C-CFD391AC7F35"><apiname>CMMFController::CustomCommand()</apiname></xref> methodcan be implemented in the controller plugin to support custom commands. Thedefault implementation provided by the base class is to complete the messagewith <codeph>KErrNotSupported</codeph>. </p> <p> <b>Note:</b> It is imperativethat the message is always completed by this method and that this method cannotleave. Any error that occurs must be passed back to the client by completingthe message with the error code. </p> <p>Each <xref href="GUID-3AF511EA-1E66-3286-9FD0-B90EC22BFAC1.dita"><apiname>TMMFMessage</apiname></xref> hasan associated interface UID which should be checked before handling any messageto make sure that the command is supported. </p> <p>The following code illustratesa typical custom command implementation. </p> <codeblock id="GUID-88B2D503-D009-502A-923A-EA683A28061B" xml:space="preserve">void CMyController::CustomCommand(TMMFMessage& aMessage) { // First, check we can handle message by checking its interface id if (aMessage.InterfaceId() != KUidMyControllerCustomCommandInterface) { aMessage.Complete(KErrNotSupported); return; } // Next, dispatch the command to the appropriate method. TInt error = KErrNone; switch (aMessage.Function()) { case EMyCustomCommandOne: error = HandleCustomCommandOne(aMessage); break; case EMyCustomCommandTwo: error = HandleCustomCommandTwo(aMessage); break; default: error = KErrNotSupported;break; } aMessage.Complete(error); }</codeblock> <p>The above example shows synchronous command handling. If theplugin needs to do some task that requires a long time, the <codeph>aMessage</codeph> parametershould be copied, stored and completed later when processing has finished. </p> <p>Themethods <codeph>HandleCustomCommandOne</codeph> and <codeph>HandleCustomCommandTwo</codeph> above,copy any data to and from the client. This can be done using the appropriate <xref href="GUID-3AF511EA-1E66-3286-9FD0-B90EC22BFAC1.dita"><apiname>TMMFMessage</apiname></xref> methods. </p> <p><b>Asynchronous Error Reporting </b> </p> <p>The <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-35FFB275-95ED-323C-B0AC-7914CBA2319D"><apiname>CMMFController::DoSendEventToClient()</apiname></xref> utilitymethod allows a controller plugin to send an event to its client. </p> <p>Themultimedia client utilities listen for specific event types and error codes.If the controller plugin is accessed by clients that are using the multimediaclient utility APIs (which will usually be the case) then those event typesand error codes should be used. The event types and error codes for whichthe multimedia client utilities listen are listed below: </p> <table id="GUID-4BE6C78B-5E14-50EF-94EB-05AFA08DFD2D"><tgroup cols="4"><colspec colname="col0"/><colspec colname="col1"/><colspec colname="col2"/><colspec colname="col3"/><tbody><row><entry><p> <b>Client utility</b> </p> </entry><entry><p> <b>Event type</b> </p> </entry><entry><p> <b>Error code</b> </p> </entry><entry><p> <b>Meaning</b> </p> </entry></row><row><entry><p>Audio Player Utility (<xref href="GUID-778D24B5-A68E-3C91-B66A-69007FBA4791.dita"><apiname>CMdaAudioPlayerUtility</apiname></xref>) </p> </entry><entry><p>Any </p> </entry><entry><p>KErrOverflow </p> </entry><entry><p>Playback complete, the end of the data was reached. </p> </entry></row><row><entry><p> </p> </entry><entry><p>Any </p> </entry><entry><p>KErrEof </p> </entry><entry><p>Playback complete, the end of the data was reached. </p> </entry></row><row><entry><p>Audio Recorder Utility (<xref href="GUID-29FB1DE6-D00C-3E6B-A8AA-476FAFD7F26C.dita"><apiname>CMdaAudioRecorderUtility</apiname></xref>) </p> </entry><entry><p>Any </p> </entry><entry><p>KErrOverflow </p> </entry><entry><p>Playback complete, the end of the data was reached. </p> </entry></row><row><entry><p> </p> </entry><entry><p>Any </p> </entry><entry><p>KErrUnderflow </p> </entry><entry><p>Recording complete, no more source data from microphone. </p> </entry></row><row><entry><p> </p> </entry><entry><p>Any </p> </entry><entry><p>KErrEof </p> </entry><entry><p>Playback or recording complete, end of data reached. </p> </entry></row><row><entry><p>Audio Converter Utility (<xref href="GUID-810D29DA-8332-3E63-8A63-5B8A04EC9688.dita"><apiname>CMdaAudioConvertUtility</apiname></xref>) </p> </entry><entry><p>Any </p> </entry><entry><p>KErrOverflow </p> </entry><entry><p>Conversion complete, end of data reached. </p> </entry></row><row><entry><p> </p> </entry><entry><p>Any </p> </entry><entry><p>KErrEof </p> </entry><entry><p>Conversion complete, end of data reached. </p> </entry></row><row><entry><p>Video Player Utility (<xref href="GUID-0F1F8AC6-B99F-3274-A785-9977197AF762.dita"><apiname>CVideoPlayerUtility</apiname></xref>) </p> </entry><entry><p>Any </p> </entry><entry><p>KErrOverflow </p> </entry><entry><p>Playback complete, end of data reached. </p> </entry></row><row><entry><p> </p> </entry><entry><p>Any </p> </entry><entry><p>KErrEof </p> </entry><entry><p>Playback complete, end of data reached. </p> </entry></row><row><entry><p> </p> </entry><entry><p>KMMFEventCategory VideoOpenComplete </p> </entry><entry><p>Any </p> </entry><entry><p>Open complete. Must be used otherwise clients will not be notifiedwhen the clip has been opened. This is used because video clips can take along time to process on opening. The error code is passed back to the client. </p> </entry></row><row><entry><p> </p> </entry><entry><p>KMMFEventCategory PlaybackComplete </p> </entry><entry><p>Any </p> </entry><entry><p>Playback complete. Can be used instead of <codeph>KErrOverflow</codeph> or <codeph>KErrEof</codeph>.The error code is passed back to the client. </p> </entry></row><row><entry><p> </p> </entry><entry><p>KMMFEventCategory VideoRebufferStarted </p> </entry><entry><p>Any </p> </entry><entry><p>Re-buffering has begun. Client will be notified so it can updateits UI. </p> </entry></row><row><entry><p> </p> </entry><entry><p>KMMFEventCategory VideoRebufferComplete </p> </entry><entry><p>Any </p> </entry><entry><p>Re-buffering has finished. Client will be notified so it can updateits UI. </p> </entry></row></tbody></tgroup></table> <p><b>MMF Objects </b> </p> <p>The controller framework contains an object referencingmechanism that allows a client to send messages to arbitrary objects in thecontroller thread without having to go via the controller plugin itself. Inorder to achieve this, the arbitrary object must be derived from <xref href="GUID-C2938956-C3DE-34F0-AD68-4E502F252FE4.dita"><apiname>CMMFObject</apiname></xref> andadded to the object container. The object container can be accessed via the <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-C13AA1D6-94D3-33EA-B901-C4EFBA127D3A"><apiname>CMMFController::MMFObjectContainerL()</apiname></xref> method. </p> <p>Sources and sinks have a <xref href="GUID-C2938956-C3DE-34F0-AD68-4E502F252FE4.dita"><apiname>CMMFObject</apiname></xref> wrapper placed aroundthem by the controller framework, and can receive messages from the client.This mechanism is also used to reference source(s) and sink(s), so the clientcan specify exactly the source or sink when calling the <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-6CA27841-ACBE-303B-84A6-225F77B6CC53"><apiname>CMMFController::RemoveDataSourceL()</apiname></xref> or <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-FD6A61E9-B355-36BA-9FF5-AA5E694F76FA"><apiname>CMMFController::RemoveDataSinkL()</apiname></xref> methods. </p> <p> <b>Note:</b> The objects added to the <xref href="GUID-C2B766A9-493D-3B90-B205-F7915B39EBAF.dita"><apiname>CMMFObjectContainer</apiname></xref> areowned by the <codeph>CMMFObjectContainer</codeph>. </p> <p>Each object addedto the <codeph>CMMFObjectContainer</codeph> is assigned a handle. This handlemust be passed back to the client in order for the client to be able to sendmessages directly to the object. </p> <p>The client should use this handleto set the handle of the <xref href="GUID-40C533CC-ACA4-3DBC-B31C-F17DACB7F321.dita"><apiname>TMMFMessageDestination</apiname></xref> parameterin the <xref href="GUID-9DEDFB0F-C963-3FB7-9237-DDDB276C8841.dita#GUID-9DEDFB0F-C963-3FB7-9237-DDDB276C8841/GUID-A3976673-6919-307E-AA6A-4E6B18D96619"><apiname>RMMFController::CustomCommandAsync()</apiname></xref> or <xref href="GUID-9DEDFB0F-C963-3FB7-9237-DDDB276C8841.dita#GUID-9DEDFB0F-C963-3FB7-9237-DDDB276C8841/GUID-E0CBE252-799E-3972-8C14-B1C6E135C458"><apiname>RMMFController::CustomCommandSync()</apiname></xref> methodfor asynchronous or synchronous operation respectively. The custom commandwill then be routed directly to the <xref href="GUID-C2938956-C3DE-34F0-AD68-4E502F252FE4.dita"><apiname>CMMFObject</apiname></xref> by the controllerframework. </p> </section><section id="GUID-C5696F98-4ECF-5086-AC1A-BF17BCFECC29"><title>Implementingthe standard custom command interfaces</title> <p>The core controller pluginAPI provides only basic support for controlling the flow of data. The application-levelmultimedia utility APIs (for example, <xref href="GUID-778D24B5-A68E-3C91-B66A-69007FBA4791.dita"><apiname>CMdaAudioPlayerUtility</apiname></xref> )contain much richer functionality. The application-level multimedia utilityAPIs provide clients with a concrete API to access extended controller functionality,and to give controller plugins a concrete mixin API to implement. </p> <p>Severalsets of standard custom command APIs have been defined. The following tableshows which of these classes must be implemented to allow the controller pluginto be used properly from each of the application-level utility APIs. </p> <table id="GUID-2B37F10D-C1B3-5449-A211-77192872974E"><tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/><tbody><row><entry><p> <b>Application-level Utility API</b> </p> </entry><entry><p> <b>Required Custom Command APIs</b> </p> </entry></row><row><entry><p> <xref href="GUID-47EA759D-94C2-3655-B6E8-6C87F8F449A9.dita"><apiname>CmdaAudioPlayerUtility</apiname></xref> </p> </entry><entry><p> <xref href="GUID-9004EBF7-A519-3825-91DC-0CB5EE2AE91E.dita"><apiname>MMMFAudioPlayDeviceCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-9EBEDC0D-2AE8-3A15-A72F-E18999056879.dita"><apiname>MMMFAudioPlayControllerCustomCommandImplementor</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-E83933DA-64D2-3B7F-ACF6-0A72E6132E16.dita"><apiname>CmdaAudioRecorderUtility</apiname></xref> </p> </entry><entry><p> <xref href="GUID-9004EBF7-A519-3825-91DC-0CB5EE2AE91E.dita"><apiname>MMMFAudioPlayDeviceCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-6257431B-91C0-3F11-B9B8-6CA07BE81DF0.dita"><apiname>MMMFAudioRecordDeviceCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-9EBEDC0D-2AE8-3A15-A72F-E18999056879.dita"><apiname>MMMFAudioPlayControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-955A29AB-D7FE-3747-A451-A75B01867675.dita"><apiname>MMMFAudioRecordControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-B9EF7125-3D50-375D-904E-2148F650765D.dita"><apiname>MMMFAudioControllerCustomCommandImplementor</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-A11E409C-894A-3C91-8924-5CF6C53D7F7D.dita"><apiname>CmdaAudioConvertUtility</apiname></xref> </p> </entry><entry><p> <xref href="GUID-9EBEDC0D-2AE8-3A15-A72F-E18999056879.dita"><apiname>MMMFAudioPlayControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-955A29AB-D7FE-3747-A451-A75B01867675.dita"><apiname>MMMFAudioRecordControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-B9EF7125-3D50-375D-904E-2148F650765D.dita"><apiname>MMMFAudioControllerCustomCommandImplementor</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-3F3FEBAA-DA64-3D83-999C-33AF27B9F0B2.dita"><apiname>CvideoPlayerUtility</apiname></xref> </p> </entry><entry><p> <xref href="GUID-4D1C7814-76D6-3A1C-9441-4091C4787826.dita"><apiname>MMMFVideoControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-1FBF69A5-100C-30D6-B934-AD208C320C52.dita"><apiname>MMMFVideoPlayControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-9004EBF7-A519-3825-91DC-0CB5EE2AE91E.dita"><apiname>MMMFAudioPlayDeviceCustomCommandImplementor</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-EA89F469-D402-34B4-9038-895ABA696AF6.dita"><apiname>CvideoRecorderUtility</apiname></xref> </p> </entry><entry><p> <xref href="GUID-4D1C7814-76D6-3A1C-9441-4091C4787826.dita"><apiname>MMMFVideoControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-E66BBFA9-17C5-30C0-88F0-2680825585D6.dita"><apiname>MMMFVideoRecordControllerCustomCommandImplementor</apiname></xref> </p> <p> <xref href="GUID-6257431B-91C0-3F11-B9B8-6CA07BE81DF0.dita"><apiname>MMMFAudioRecordDeviceCustomCommandImplementor</apiname></xref> </p> </entry></row></tbody></tgroup></table> <p>In order to implement the required custom command APIs, the controllerplugin should derive from the mixins shown in the table above, and use the <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-DAB14DA3-E897-3C57-ADAC-8748D6B06E7B"><apiname>CMMFController::AddCustomCommandParserL()</apiname></xref> methodto register itself as being able to handle that API. </p> <p>The <xref href="GUID-92F9FFAA-1A8F-34B4-98E4-7BAF505BDE45.dita"><apiname>CMMFCustomCommandParserBase</apiname></xref> derivedobject decodes the custom command on behalf of the controller plugin and callsthe concrete API via the mixin interface. The following table shows which <xref href="GUID-92F9FFAA-1A8F-34B4-98E4-7BAF505BDE45.dita"><apiname>CMMFCustomCommandParserBase</apiname></xref> objectshould be used with each mixin class. </p> <table id="GUID-7C4650A0-ED5A-5B9B-8349-3B348D16DCBB"><tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/><tbody><row><entry><p> <b>Mixin Interface</b> </p> </entry><entry><p> <b>Custom Command Parser</b> </p> </entry></row><row><entry><p> <xref href="GUID-B9EF7125-3D50-375D-904E-2148F650765D.dita"><apiname>MMMFAudioControllerCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-0E8AE2BE-D2E4-31D1-A9EE-8C134AC08A44.dita"><apiname>CMMFAudioControllerCustomCommandParser</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-9EBEDC0D-2AE8-3A15-A72F-E18999056879.dita"><apiname>MMMFAudioPlayControllerCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-4446548D-A1C6-37E9-8C93-5DE06BC9733F.dita"><apiname>CMMFAudioPlayControllerCustomCommandParser</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-955A29AB-D7FE-3747-A451-A75B01867675.dita"><apiname>MMMFAudioRecordControllerCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-F37B8FE6-ABD8-311A-89CA-3495FE88EE32.dita"><apiname>CMMFAudioRecordControllerCustomCommandParser</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-4D1C7814-76D6-3A1C-9441-4091C4787826.dita"><apiname>MMMFVideoControllerCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-4C75EEA6-3F0E-3EDE-B02C-83B8AE6F4563.dita"><apiname>CMMFVideoControllerCustomCommandParser</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-1FBF69A5-100C-30D6-B934-AD208C320C52.dita"><apiname>MMMFVideoPlayControllerCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-E45B8292-04DE-3929-8E10-46E8D259A3B3.dita"><apiname>CMMFVideoPlayControllerCustomCommandParser</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-E66BBFA9-17C5-30C0-88F0-2680825585D6.dita"><apiname>MMMFVideoRecordControllerCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-7BF02827-4A99-3127-873A-BA5D5CD1DFDB.dita"><apiname>CMMFVideoRecordControllerCustomCommandParser</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-9004EBF7-A519-3825-91DC-0CB5EE2AE91E.dita"><apiname>MMMFAudioPlayDeviceCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-C27DB2A9-1AD6-3AA2-A9A7-F97D8B493B20.dita"><apiname>CMMFAudioPlayDeviceCustomCommandParser</apiname></xref> </p> </entry></row><row><entry><p> <xref href="GUID-6257431B-91C0-3F11-B9B8-6CA07BE81DF0.dita"><apiname>MMMFAudioRecordDeviceCustomCommandImplementor</apiname></xref> </p> </entry><entry><p> <xref href="GUID-CAB4C3DA-43E3-37C5-B9BD-0DE3341A7D59.dita"><apiname>CMMFAudioRecordDeviceCustomCommandParser</apiname></xref> </p> </entry></row></tbody></tgroup></table> <p>The following example code shows how the controller should registeritself with the controller framework to receive standard custom commands. </p> <codeblock id="GUID-DDC6EA9D-C01D-599D-9ADA-F3445675D252" xml:space="preserve">class CMyControllerPlugin : public CMMFController, MMMFAudioControllerCustomCommandImplementor, MMMFAudioPlayDeviceCustomCommandImplementor {...private: void ConstructL(); };void CMyControllerPlugin::ConstructL() {... // Construct custom command parsers CMMFAudioControllerCustomCommandParser* audConParser = CMMFAudioControllerCustomCommandParser::NewL(*this); CleanupStack::PushL(audParser); AddCustomCommandParserL(*audConParser); //parser now owned by controller framework CleanupStack::Pop(audConParser); CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser = CMMFAudioPlayDeviceCustomCommandParser::NewL(*this); CleanupStack::PushL(audPlayDevParser); AddCustomCommandParserL(*audPlayDevParser); //parser now owned by controller framework CleanupStack::Pop();//audPlayDevParser }</codeblock> <p>It is also possible for controller plugins to define theirown standard custom command classes. This might be useful if a group of pluginshave the same API (for example, a group of <codeph>MIDI</codeph> controllerplugins). Clients would then be able to access equivalent functionality ineach plugin using the same API. </p> </section><section id="GUID-A305F052-58F4-57B9-AB0F-C172768E462F"><title>Interactionwith MMF Base Classes and other Plugins</title> <p>The MMF provides a setof utility classes and other types of plugins to aid with writing controllerplugins. All utility classes are provided in the library <codeph>MMFServerBaseClasses.DLL</codeph>.A brief description of each of the classes follows. </p> <p> <b>Note:</b> Theuse of data sources, data sinks and buffers is mandatory. The use of the otherclasses is optional. </p> <ul><li id="GUID-55EAC53C-8F71-5A3B-AE7C-695EBC3C53D0"><p>Data Sources and Sinks </p> </li><li id="GUID-EF0BF115-FF08-56FE-90C7-CF48D85A6C0B"><p>Buffers </p> </li><li id="GUID-4B99F28F-8EB3-5B66-B9BF-8AEE3DA5253E"><p>Datapath </p> </li><li id="GUID-C5CAE5D5-7C82-5068-9AAB-6D9E66DE5D6B"><p>Codecs </p> </li><li id="GUID-174E2D35-3208-5AEA-8257-4952E147F72D"><p>Formats </p> </li></ul> <p><b>Data Sources and Sinks </b> </p> <p>Data sources and sinks are <xref href="GUID-9E92EE30-F2E2-5F28-BB2A-391C09EC69D2.dita">ECom</xref> plugins,and are derived from the base class <xref href="GUID-2230F976-A798-30EB-ABA6-09C86716A4B5.dita"><apiname>MDataSource</apiname></xref> or <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita"><apiname>MDataSink</apiname></xref> respectively.The currently available data sources and sinks are listed below: </p> <ul><li id="GUID-E7874D8E-528E-50BE-9BBE-1F3B721D0274"><p> <xref href="GUID-9914ABBD-B15F-3CDB-9F4E-1C9002A30269.dita"><apiname>CMMFFile</apiname></xref> </p> </li><li id="GUID-52F6F014-B4AA-5301-A099-19A7B3415CD0"><p> <xref href="GUID-ADF29263-C4FB-31A8-AB06-0E10E39B7C39.dita"><apiname>CMMFDescriptor</apiname></xref> </p> </li><li id="GUID-52A43340-E2C7-56BE-BA1E-AF96A49DD8F2"><p> <xref href="GUID-D9BCF418-34D3-3D47-8968-A70C5C01E5DF.dita"><apiname>CMMFAudioInput</apiname></xref> </p> </li><li id="GUID-C95CADA7-9917-5C4E-A93D-1E16CB34171F"><p> <xref href="GUID-CB3745FF-6DC0-325A-95CC-70BF5112DD70.dita"><apiname>CMMFAudioOutput</apiname></xref> <xref href="GUID-D9BCF418-34D3-3D47-8968-A70C5C01E5DF.dita"><apiname>CMMFAudioInput</apiname></xref> </p> </li></ul> <p>They are created by the controller framework and passed into thecontroller plugin by reference using the <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-11623B04-A83E-3E32-A06E-6454D8407ADB"><apiname>CMMFController::AddDataSourceL()</apiname></xref> or <xref href="GUID-123B3A78-9E84-3283-AB73-6B4293939A5D.dita#GUID-123B3A78-9E84-3283-AB73-6B4293939A5D/GUID-8842FF05-7822-317A-A650-225775B758FD"><apiname>CMMFController::AddDataSinkL()</apiname></xref> method. </p> <p>Some sources and sinks have extended APIs that allow the controller pluginto perform actions, such as setting the volume. The type of the source orsink can be checked by the controller plugin using the methods <xref href="GUID-2230F976-A798-30EB-ABA6-09C86716A4B5.dita#GUID-2230F976-A798-30EB-ABA6-09C86716A4B5/GUID-D931704C-4349-36EE-9E05-BADF10253373"><apiname>MDataSource::DataSourceType()</apiname></xref> and <xref href="GUID-708A7583-5C55-3FE1-8238-974C8821588D.dita#GUID-708A7583-5C55-3FE1-8238-974C8821588D/GUID-E03D973E-75A5-3FBA-9D24-04A5F6B23A7C"><apiname>MDataSink::DataSinkType()</apiname></xref>. These methods return a UID which can be checked against known UIDs to identifythe extended API of the source or sink. For example, the following code wouldbe used to set the volume of a speaker sink. </p> <codeblock id="GUID-8CCA0B72-6A76-5235-B397-17745DAB1A18" xml:space="preserve">MMMFAudioOutput* audioOutput = static_cast(MMMFAudioOutput*,(iDataSink));audioOutput->SoundDevice().SetVolume(14);</codeblock> <p>It is possible dynamically to add new data sources and sinksto the system, see <xref href="GUID-2062A92D-2A3C-5D38-B25E-6D4CF3E4BC98.dita">writinga Source/Sink plugin</xref> for information. </p> <p><b>Buffers </b> </p> <p>Buffers are used to contain data as it is being transferredfrom a source to a sink. There are several buffer types all derived from acommon base class <xref href="GUID-9A7A83ED-592B-3A0C-BABB-3B90099BCF7C.dita"><apiname>CMMFBuffer</apiname></xref>: <xref href="GUID-AE26E6A4-C1AD-3B35-B5F7-CE0AB60169BB.dita"><apiname>CMMFDataBuffer</apiname></xref>, <xref href="GUID-74A246CD-24ED-3506-9E98-0C6A7EFD1AC3.dita"><apiname>CMMFDescriptorBuffer</apiname></xref> and <xref href="GUID-4899998E-6DE7-3A9F-874B-6B4524CE33E4.dita"><apiname>CMMFTransferBuffer</apiname></xref>. </p> <p><b>Datapath </b> </p> <p>The datapath is a utility class that transfers datafrom a single source to a single sink, via a codec plugin if the source andsink data types differ. The API of the datapath is very similar to that ofthe basic controller plugin API, and much of the complexity of controllerplugins can be avoided by using the datapath. </p> <p>The datapath can beused either through: </p> <ul><li id="GUID-12E661D0-9317-551F-8D9E-876AF0153CCC"><p> <xref href="GUID-930A17D8-92C9-379A-A524-176AA68FE8E3.dita"><apiname>CMMFDataPath</apiname></xref>,in which case the data will be transferred from the source to the sink inthe main thread of the controller plugin. </p> </li><li id="GUID-B7B80AD5-7977-56C7-92A6-A722C66FA7EA"><p> <xref href="GUID-1869F1F6-AEAE-3932-8A9C-54B641CE9CD5.dita"><apiname>RMMFDataPath</apiname></xref>,in which case a new thread will be launched to transfer the data from thesource to the sink. This is useful if a controller has multiple sources andsinks (a video controller for example). The multiple datapaths can each beexecuted in their own thread to improve performance. </p> </li></ul> <p>If the source and sink data types are the same then no codec is requiredand the datapath will use a <codeph>null</codeph> codec and the buffers willbe transferred straight from the source to the sink without being copied inbetween. </p> <p><b>Codecs </b> </p> <p>Codec plugins are derived from <xref href="GUID-18F4082A-D301-3007-88DD-0E13AB81C74A.dita"><apiname>CMMFCodec</apiname></xref> andcan be used by controller plugins to convert data from one data type to another.Codec plugins are designed to be used by different controller plugins, forexample both an audio controller and a video controller might want to makeuse of a <codeph>PCM8</codeph> to <codeph>PCM16</codeph> codec. </p> <p>See <xref href="GUID-7261FEC6-5AA6-555C-AB72-2173BD3F1FA5.dita">writing a codec plugin</xref> fordetails of how to implement codec plugins. </p> <p><b>Formats </b> </p> <p>Controller plugin writers may wish to implement theirformat support by writing format plugins. While format plugins can only beused by one controller plugin, this does make it much easier to dynamicallyextend the formats supported by the controller plugin without providing awhole new controller plugin. See <xref href="GUID-BDC081CA-FB0D-5F56-8C1B-F7AC9DD6875D.dita">writinga format plugin</xref> for details of how to implement format plugins. </p> </section><section id="GUID-9FD6AAA8-4024-578F-9AB4-48F7017D3EB6"><title>Integratingthe Controller into the ECom Plugin Framework</title> <p>This section describeshow to write the ECom plugin registry file. See <xref href="GUID-9E92EE30-F2E2-5F28-BB2A-391C09EC69D2.dita">ECom</xref> forgeneric instructions on how to write an ECom plugin. </p> <p>The controllerplugin resolver is decides which controller plugin should be used to providesupport for a particular format. Controller plugins provide information intheir <codeph>ECom</codeph> resource file which allows the controller framework(and ultimately the client application) to determine: </p> <ul><li id="GUID-B14BEDD7-34F4-5EB6-A0C3-EAFD2427254D"><p>The display name andsupplier of the controller plugin. </p> </li><li id="GUID-CCE1BACF-7EA4-5160-A132-387BB2E27BE1"><p>The media types supportedby the controller plugin (e.g. audio or video). </p> </li><li id="GUID-2207F37F-C06F-5E7C-A92F-2B07D4E19CDE"><p>The formats the controllerplugin can play and record. </p> </li></ul> <p>For each format supported, for both playing and recording, the informationbelow is provided: </p> <ul><li id="GUID-9BE53029-AE39-5A88-802D-7907936D23D4"><p>Display Name of theformat. </p> </li><li id="GUID-D4E3EA7C-BE26-5CC5-ABFA-80F37C662D9C"><p>Supplier of the format(in case support for this format was provided by a different party to thecontroller plugin). </p> </li><li id="GUID-0222405C-A868-5C71-900D-0181F071E718"><p>The Media Types supportedby the format. </p> </li><li id="GUID-3D9FE26B-DF8A-58D8-BDDC-CCD55FEEBBF9"><p>The MIME types applicableto the format. </p> </li><li id="GUID-EC8EB39A-6C09-50AD-90F8-48C7E7A9B356"><p>The file extensionsthat identify files that can be handled by the format. </p> </li><li id="GUID-EF2278A1-9878-5408-B689-A27A181C5855"><p>Any header data segmentsthat could be matched to the first few bytes of multimedia data to identifythat the data could be handled using this format. </p> </li></ul> <p>Most of the information outlined above is provided by the pluginin the <codeph>opaque_data</codeph> field of the ECom resource file. Thisfield takes an 8-bit string and is limited to 127 characters in length. Atagged data scheme is used to separate the different types of data. The tagsare all three characters in length, and the scheme only uses opening tags(i.e. no end tags) to reduce overhead and complexity. The tags available are: </p> <table id="GUID-1F208E5B-912E-5973-BB47-0A84F917CF23"><tgroup cols="3"><colspec colname="col0"/><colspec colname="col1"/><colspec colname="col2"/><tbody><row><entry><p>Tag </p> </entry><entry><p>Usage </p> </entry><entry><p>Description </p> </entry></row><row><entry><p><s> </p> </entry><entry><p>Controller, Format </p> </entry><entry><p>The supplier of the plugin. </p> </entry></row><row><entry><p><i> </p> </entry><entry><p>Controller, Format </p> </entry><entry><p>A media ID supported by this plugin. Multiple entries can be included. </p> </entry></row><row><entry><p><p> </p> </entry><entry><p>Controller </p> </entry><entry><p>The UID of the play format collection for this controller (see below). </p> </entry></row><row><entry><p><r> </p> </entry><entry><p>Controller </p> </entry><entry><p>The UID of the record format collection for this controller (seebelow). </p> </entry></row><row><entry><p><m> </p> </entry><entry><p>Format </p> </entry><entry><p>A mime type that describes the format. Multiple entries with thistag can be included. </p> </entry></row><row><entry><p><e> </p> </entry><entry><p>Format </p> </entry><entry><p>A file extension supported by this format. Multiple entries withthis tag can be included. </p> </entry></row><row><entry><p><h> </p> </entry><entry><p>Format </p> </entry><entry><p>A segment of header data that can be matched against the first fewbytes of a clip to check whether this format is capable of handling the clip.Multiple entries with this tag can be included. </p> </entry></row></tbody></tgroup></table> <p>Formats can be supported by controller plugins either: </p> <ul><li id="GUID-D7548E83-D055-5444-B53C-DDEBE26EB84C"><p> <b>Internally:</b> Inthis case, the controller is able to read or write the format by itself. Controllerplugins can specify the formats they support internally with extra entriesin their plugin resource file. They define two new <xref href="GUID-9E92EE30-F2E2-5F28-BB2A-391C09EC69D2.dita">ECom</xref> plugininterface uids (one for play formats, the other for record formats) in their <codeph>opaque_data</codeph> fieldusing the tags <codeph><p></codeph> and <codeph><r></codeph>. The playformats they support are then listed as <codeph>ECom</codeph> plugin implementationsof the play format interface UID, and likewise with the record formats. Theseinterface UIDs and implementations do not correspond to any real plugins.They are simply a way of letting the controller framework know exactly whichformats the controller supports in a scalable manner. The implementation UIDsof each format should be known to the controller so that a client can specifythe format that a controller should use by using this UID. </p> </li><li id="GUID-DAA4BF7F-D830-5A8B-A2D9-EA6B1BB6D9C0"><p> <b> By using formatplugins:</b> The <xref href="GUID-8BAA3621-DC04-357F-8342-D72A313CCA86.dita"><apiname>MMFServerBaseClasses</apiname></xref> component definesbase classes for both encoding and decoding format plugins. By using formatplugins, the formats supported by a controller plugin can be extended dynamicallywithout having to change the controller plugin itself. The <xref href="GUID-9E92EE30-F2E2-5F28-BB2A-391C09EC69D2.dita">ECom</xref> pluginresource file of each format plugin contains the UID of the controller pluginthat it extends, allowing the controller framework to build up an accuratepicture of the formats supported by each controller. </p> </li></ul> <p>The following is an example of a resource file for an audio controllerplugin that supports playing <codeph>WAV</codeph> and <codeph>AU</codeph>,and recording <codeph>AU</codeph>. </p> <codeblock id="GUID-E9D08E5B-F29E-5668-83CC-74B39AAA139D" xml:space="preserve">RESOURCE REGISTRY_INFO theInfo { dll_uid = 0x101F1234; interfaces = { INTERFACE_INFO // Controller Plugin Description { interface_uid = KMmfUidPluginInterfaceController ; implementations = { IMPLEMENTATION_INFO { implementation_uid = 0x101F1235 ; version_no = 1; display_name = "Symbian Audio controller"; default_data = "?"; opaque_data = “<s>Symbian<i>0x101F5D07<p>0x101F0001<r>0x101F0002"; // SUPPLIER = Symbian // MEDIA ID = uid for audio media type // PLAY FORMATS = look at interface uid 0x101f0001 // RECORD FORMATS = look at interface uid 0x101f0002 } }; }, INTERFACE_INFO // Play Formats Description { interface_uid = 0x101F0001 ; implementations = { IMPLEMENTATION_INFO { implementation_uid = 0x101F1236 ; version_no = 1; display_name = "WAV Play Format"; default_data = "?"; opaque_data = “<s>Symbian<i>0x101f5d07<e>.wav<h>RIFF????WAVE<m>Audio/Wave"; // SUPPLIER = Symbian // MEDIA ID = uid for audio media type // FILE EXTENSION = .wav // HEADER DATA = look for RIFF????WAVE in header data. The’?’s // indicate a single character wildcard. // MIME TYPE = Audio/Wave }, IMPLEMENTATION_INFO { implementation_uid = 0x101F1237 ; version_no = 1; display_name = "AU Play Format"; default_data = "?"; opaque_data = “<s>Symbian<i>0x101f5d07<e>.au<h>.snd"; // SUPPLIER = Symbian // MEDIA ID = uid for audio media type // FILE EXTENSION = .au // HEADER DATA = look for .snd in header data. // MIME TYPE = No mime type } }; }, INTERFACE_INFO // Record Formats Description { interface_uid = 0x101F0002 ; implementations = { IMPLEMENTATION_INFO { implementation_uid = 0x101F1238 ; version_no = 1; display_name = "WAV Record Format"; default_data = "?"; opaque_data = “<s>Symbian<i>0x101f5d07<e>.wav<h>RIFF????WAVE<m>Audio/Wave"; // SUPPLIER = Symbian // MEDIA ID = uid for audio media type // FILE EXTENSION = .wav // HEADER DATA = look for RIFF????WAVE in header data. The’?’s // indicate a single character wildcard. // MIME TYPE = Audio/Wave } }; } }; }</codeblock> <p> <b>Note:</b> The <codeph>default_data</codeph> field is notused by the controller framework. A <codeph>UTF8</codeph> to <codeph>unicode</codeph> conversionis performed on the Supplier. All other data is left in <codeph>ascii</codeph>. </p> </section><section id="GUID-0F96339A-BF77-570C-908D-A59AFD2036DB"><title>Testing</title> <p>Thecontroller plugin should be tested by exercising any application-level utilityAPIs that are meant to be supported by the plugin. For example, a video playercontroller would be tested using the <xref href="GUID-FFD6114E-36B4-3176-ABDD-987DDA2F2099.dita"><apiname>CVideoPlayer</apiname></xref> API. </p> </section></conbody><related-links><link href="GUID-3E341F9F-2635-589B-A59A-B999FE7DF9BE.dita"><linktext>MultimediaAPIs and Frameworks</linktext></link></related-links></concept>