diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-AC560324-798C-5D0A-B23D-2419A7688A5B.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-AC560324-798C-5D0A-B23D-2419A7688A5B.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,583 @@ + + + + + +Channel +ImplementationDescribes how to implement the physical channels with the template +port. +

A Sound Driver PDD must implement physical channels to use the audio hardware +of the phone. The main Sound Driver PDD class is derived from DSoundScPdd. +A Sound Driver PDD that provides record and playback functions must implement +a record driver channel and a playback driver channel.

+

The template defines two classes: DTemplateSoundScRxPdd and DTemplateSoundScTxPdd, +corresponding to record and playback respectively. The classes provide default +implementations for the virtual functions defined by DSoundScPdd, +together with a constructor and destructor, and typically need little or no +modification.

+
PDD class constructor

Implement +the PDD class constructor for both the playback and record driver channels. +This is normally limited to

    +
  • initialising any data +members that need values other than zero

  • +
  • initialising any DFC +call-backs added.

  • +

Access to hardware has the potential to fail and so should be deferred +to the second stage constructor DoCreate().

+
PDD class destructor

Implement +the PDD class destructor for both the playback and record driver channels. +The destructor must release any hardware and Symbian platform resources that +have been allocated to the driver. For example, this might include:

    +
  • unbinding ISRs

  • +
  • cancelling private DFCs

  • +
  • closing DMA channels

  • +
  • deleting any mono-to-stereo +conversion buffers

  • +

The template versions of this function delete each DMA request object +created in the PDD second stage constructor DSoundScPdd::DoCreate() and +close the DMA channel.

+
DoCreate()

Implement +a PDD class second stage constructor for both the playback and record driver +channels. In the template version, the function DSoundScPdd::DoCreate() is +called from the PDD factory when a channel is opened on the device. Generally, +any hardware or Symbian platform resources required by the driver +channel should be acquired here. However, powering up the sound device should +be deferred to the PowerUp() function. +Operations performed by this function include:

    +
  • binding an ISR to an +audio related interrupt

  • +
  • open a DMA channel

  • +
  • allocate a mono-to-stereo +conversion buffer

  • +

The template versions of this function include code to set up a DMA +channel. This involves opening a DMA channel in the appropriate direction +for the driver channel and then allocating a set of DMA request objects. However, +to use this implementation you must supply the missing platform specific information:

    +
  • Provide values for the +maximum number of DMA requests outstanding on the DMA channel. These values +determine the number of separate DMA request objects allocated for the DMA +channel, and so the number of transfer fragments that the PDD can accept from +the LDD at any time. See playback and record.

  • +
  • Set the appropriate +DMA values for your device within the file soundsc_plat.h. +These values, renamed in section copying +the template port implementation to reflect your device name, are KTemplateMaxTxDmaRequests or KTemplateMaxRxDmaRequests for playback and record respectively.

  • +
  • Setup the DMA channel +information for the device. This includes the following members of TDmaChannel::SCreateInfo.

      +
    • iCookie: +The platform specific ID used by the DMA controller to select the DMA channel +to open.

    • +
    • iDesCount: +The number of DMA descriptors the DMA controller should create. This is typically +set with the same value as KTemplateMaxTxDmaRequests or KTemplateMaxRxDmaRequests.

    • +
    • iDfcQ: +The DFC queue to use to service DMA interrupts. This should point to the same +DFC queue that is returned to the LDD for client request handling. See the DfcQ() section.

    • +
    • iDfcPriority: +The DFC priority. This should be set to a higher value than that used by the +LDD for handling client requests. For example, higher than one.

    • +
  • +
+
DfcQ()

Make +sure that the template version of the DSoundScPdd::DfcQ() function +is appropriate for your configuration. This function has the following signature:

TDfcQue* DfcQ()

The +supplied implementation is as follows

TDfcQue* DTemplateSoundScTxPdd::DfcQ() + { + return(iPhysicalDevice->iDfcQPtr); + }

Many requests are executed in the context of a kernel-side +thread. Rather than assign a kernel thread for the driver in the LDD, the +Sound Driver allows the PDD to specify the DFC thread returned via the DfcQ() function, +which it calls when the driver channel is opened.

The default implementation +for the record and playback driver channels, returns a pointer to the DFC +queue created by the PDD factory class.

See also Implementing +the PDD factory

+
GetChunkCreateInfo()

Implement +the DSoundScPdd::GetChunkCreateInfo() function for both +the playback and record driver channels. This function has the following signature:

void DSoundScPdd::GetChunkCreateInfo(TChunkCreateInfo& aChunkCreateInfo)

The +supplied implementation is as follows:

void DTemplateSoundScTxPdd::GetChunkCreateInfo(TChunkCreateInfo& aChunkCreateInfo) + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::GetChunkCreateInfo")); + + // TO DO: (mandatory) + // Setup the shared chunk create information in aChunkCreateInfo for this play device. + aChunkCreateInfo.iType=TChunkCreateInfo::ESharedKernelMultiple; + // aChunkCreateInfo.iMapAttr=??? + aChunkCreateInfo.iOwnsMemory=ETrue; // Using RAM pages. + aChunkCreateInfo.iDestroyedDfc=NULL; // No chunk destroy DFC. + }

The PDD must initialise the TChunkCreateInfo object +with the information that defines the characteristics of the shared chunk +required for the audio device. This function is called by the LDD just before +it creates a shared chunk for the channel, in response to an RSoundSc::SetBufferChunkCreate() request +from the client.

Values for the following data members must be supplied +by the PDD:

    +
  • TChunkCreateInfo::iType

  • +
  • TChunkCreateInfo::iMapAttr

  • +
  • TChunkCreateInfo::iOwnsMemory

  • +
  • TChunkCreateInfo::iDestroyedDfc

  • +

The data member TChunkCreateInfo::iMaxSize is +calculated by the LDD so there is no need to define it.

See How to share chunks.

+
Caps()

Implement +the DSoundScPdd::Caps() function for both the playback +and record driver channels. The function has the following signature:

void DSoundScPdd::Caps(TDes8& aCapsBuf) const

The +supplied implementation is as follows:

void DTemplateSoundScTxPdd::Caps(TDes8& aCapsBuf) const + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::Caps")); + + // Copy iCaps back. + TPtrC8 ptr((const TUint8*)&iCaps,sizeof(iCaps)); + aCapsBuf.FillZ(aCapsBuf.MaxLength()); + aCapsBuf=ptr.Left(Min(ptr.Length(),aCapsBuf.MaxLength())); + }

TSoundFormatsSupportedV02 is the +main audio capabilities class. The PDD must fill this object with the capabilities +for the particular audio device. the LDD uses this to get the play or record +capabilities of a particular sound device once a driver channel to the device +has been opened.

Values for the following variables must be supplied +by the PDD:

    +
  • TSoundFormatsSupportedV02::iDirection

      +
    • ESoundDirRecord

    • +
    • ESoundDirPlayback

    • +
  • +
  • TSoundFormatsSupportedV02::iChannels

      +
    • KSoundMonoChannel

    • +
    • KSoundStereoChannel

    • +
    • KSoundThreeChannel

    • +
    • KSoundFourChannel

    • +
    • KSoundFiveChannel

    • +
    • KSoundSixChannel

    • +
  • +
  • TSoundFormatsSupportedV02::iRates

      +
    • KSoundRate7350Hz

    • +
    • KSoundRate8000Hz

    • +
    • KSoundRate8820Hz

    • +
    • KSoundRate9600Hz

    • +
    • KSoundRate11025Hz

    • +
    • KSoundRate12000Hz

    • +
    • KSoundRate14700Hz

    • +
    • KSoundRate16000Hz

    • +
    • KSoundRate22050Hz

    • +
    • KSoundRate24000Hz

    • +
    • KSoundRate29400Hz

    • +
    • KSoundRate32000Hz

    • +
    • KSoundRate44100Hz

    • +
    • KSoundRate48000Hz

    • +
  • +
  • TSoundFormatsSupportedV02::iEncodings

      +
    • KSoundEncodings8BitPCM

    • +
    • KSoundEncodings16BitPCM

    • +
    • KSoundEncodings24BitPCM

    • +
  • +
  • TSoundFormatsSupportedV02::iDataFormats

      +
    • KSoundDataFormatInterleaved

    • +
    • KSoundDataFormatNonInterleaved

    • +
  • +
  • TSoundFormatsSupportedV02::iRequestMinSize

  • +
  • TSoundFormatsSupportedV02::iRequestAlignment

  • +
  • TSoundFormatsSupportedV02::iHwConfigNotificationSupport

  • +

Many of the attribute ranges are passed as bit settings, and can +assume all the values independently of one another.

The following +is a portion of the Caps() function for the template port +for the playback path of the AC97 Controller Unit (UCB140) codec device.

The +PDD maintains a TSoundFormatsSupportedV02 object as one +of its data members named iCaps. The contents of iCaps is +copied into the descriptor and passed as an argument to the Caps() function:

void DTemplateSoundScTxPdd::Caps(TDes8& aCapsBuf) const + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::Caps")); + + // Copy iCaps back. + TPtrC8 ptr((const TUint8*)&iCaps,sizeof(iCaps)); + aCapsBuf.FillZ(aCapsBuf.MaxLength()); + aCapsBuf=ptr.Left(Min(ptr.Length(),aCapsBuf.MaxLength())); + } +

The data member iCaps is initialised by the +function SetCaps() called from the second stage constructor +of the PDD object:

void DTemplateSoundScTxPdd::SetCaps() + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::SetCaps")); + + // The data transfer direction for this unit is play. + iCaps.iDirection=ESoundDirPlayback; + + // TO DO: (mandatory) + // Setup the rest of the capabilities structure DTemplateSoundScTxPdd::iCaps with the capabilities of this + // audio playback device. + }
+
MaxTransferLen()

Implement +the DSoundScPdd::MaxTransferLen() function for both playback +and record driver channels. The function has the following signature:

TInt DSoundScPdd::MaxTransferLen() const

The +supplied implementation is as follows:

TInt DTemplateSoundScTxPdd::MaxTransferLen() const + { + return(KTemplateMaxTxDmaTransferLen); + }

This function is called each time the LDD alters the +audio configuration of the channel. For example, after calling DSoundScPdd::SetConfig(). +The LDD uses the value returned to fragment record and playback data transfers +so that they are manageable by the PDD. See playback and record.

The +value returned by MaxTransferLen() is not as important +for PDDs that use the Symbian DMA framework because the DMA framework handles +fragmentation.

If the PDD has to employ mono-to-stereo data conversion +using a conversion buffer when configured in mono mode, then it needs to return +the value that corresponds with the size of the conversion buffer each time +it is configured in mono mode. See mono +to stereo conversion.

+
PowerUp()

Implement +the DSoundScPdd::PowerUp function for both the playback +and record driver channels. The function has the following signature:

TInt DSoundScPdd::PowerUp()

The +supplied implementation is as follows:

TInt DTemplateSoundScTxPdd::PowerUp() + { + // TO DO: (mandatory) + // Power up the audio device. + + return(KErrNone); + }

This function initialises the codec device and any associated +controller hardware that allows the CPU to communicate with it. However, at +this stage only basic initialisation of these hardware components is required, +as the specific audio configuration has not yet been specified, and data transfer +has not yet started.

If the PDD supports both record and playback +driver channels then most, if not all, of this hardware initialisation is +common to both channels. It may be necessary to ensure that such initialisation +on one channel cannot interfere with the other. For example, when calling DSoundScPdd::PowerUp() on +the record driver channel while the playback driver channel is active, make +sure that it does not interfere with audio playback. This typically requires +hardware status information to be held in the PDD factory object that is common +to both channels.

+
SetConfig()

Implement +the DSoundScPdd::SetConfig() function for both playback +and record driver channels. The function has the following signature:

TInt DSoundScPdd::SetConfig(const TDesC8& aConfigBuf) TInt DTemplateSoundScTxPdd::SetConfig(const TDesC8& aConfigBuf) + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::SetConfig")); + + // Read the new configuration from the LDD. + TCurrentSoundFormatV02 config; + TPtr8 ptr((TUint8*)&config,sizeof(config)); + Kern::InfoCopy(ptr,aConfigBuf); + + // TO DO: (mandatory) + // Apply the specified audio configuration to the audio device. + TInt r=KErrNone; + + __KTRACE_SND(Kern::Printf("<DTemplateSoundScTxPdd::SetConfig - %d",r)); + return(r); + }

A configuration buffer in a packaged TCurrentSoundFormatV02 object +containing the new configuration settings.

    +
  • TCurrentSoundFormatV02::iChannels

  • +
  • TCurrentSoundFormatV02::iRate

      +
    • ESoundRate7350Hz

    • +
    • ESoundRate8000Hz

    • +
    • ESoundRate8820Hz

    • +
    • ESoundRate9600Hz

    • +
    • ESoundRate11025Hz

    • +
    • ESoundRate12000Hz

    • +
    • ESoundRate14700Hz

    • +
    • ESoundRate16000Hz

    • +
    • ESoundRate22050Hz

    • +
    • ESoundRate24000Hz

    • +
    • ESoundRate29400Hz

    • +
    • ESoundRate32000Hz

    • +
    • ESoundRate44100Hz

    • +
    • ESoundRate48000Hz

    • +
  • +
  • TCurrentSoundFormatV02::iEncoding

      +
    • ESoundEncoding8BitPCM

    • +
    • ESoundEncoding16BitPCM

    • +
    • ESoundEncoding24BitPCM

    • +
  • +
  • TCurrentSoundFormatV02::iDataformat

      +
    • ESoundDateFormatInterleaved

    • +
    • ESoundDateFormatNonInterleaved

    • +
  • +

The PDD must read and locally save the contents of the TCurrentSoundFormatV02 configuration +object that has been passed as a descriptor from the LDD. The template version +contains the following code to achieve this:

// Read the new configuration from the LDD. +TCurrentSoundFormatV02 config; +TPtr8 ptr((TUint8*)&config, sizeof(config)); +Kern::InfoCopy(ptr, aConfigBuf);

It is not necessary to check +for configurations requested by the LDD that are not supported by the audio +hardware device if the Caps() function has been implemented +correctly by the PDD. This is because the LDD rejects such audio configuration +requests from the client. However, if the PDD supports both playback and record +driver channels then it needs to check that the specified configuration does +not conflict with one already in use by the other channel.

The PDD +sets up the audio hardware device according to the audio configuration specified +if it is required. Some, if not all of this hardware configuration may be +put off until data transfer is started, this is when DSoundScPdd::StartTransfer() is +called, so for now the PDD needs to save the configuration.

If the +PDD has to employ mono-to-stereo conversion of data using a conversion buffer +while the audio configuration is set to mono, then the memory for the conversion +buffer should be allocated at this time.

+
SetVolume()

Implement +the DSoundScPdd::SetVolume function for both the playback +and record driver channels. This has the following signature:

TInt DSoundScPdd::SetVolume(TInt aVolume)

The +supplied implementation is as follows:

TInt DTemplateSoundScTxPdd::SetVolume(TInt aVolume) + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::SetVolume")); + + // TO DO: (mandatory) + // Set the specified play volume on the audio device. + TInt r=KErrNone; + + return(r); + }

The PDD must first convert the volume/record level information +specified into a form which can be used to program the hardware. This may +require converting the value from a gain factor to an attenuation factor and/or +applying a scaling factor. The LDD detects situations where the client specifies +a record level /volume that is already in effect, and in this case does not +unnecessarily call the PDD.

The PDD may opt to setup the audio hardware +device within this function or it may defer this until data transfer is started +with the function DSOundScPdd::StartTransfer(). For PDDs +which support both record and playback driver channels, it is normal for audio +devices to allow the record and playback gains to be programmed independently, +this means that checking for conflicts between the channels is rarely required +for this function.

+
StartTransfer()

Implement +the DSoundScPdd::StartTransfer function for both the playback +and record driver channels. This has the following signature:

TInt DSoundScPdd::StartTransfer()

The +supplied implementation is as follows:

TInt DTemplateSoundScTxPdd::StartTransfer() + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::StartTransfer")); + + // TO DO: (mandatory) + // Prepare the audio device for playback. + TInt r=KErrNone; + + __KTRACE_SND(Kern::Printf("<DTemplateSoundScTxPdd::StartTransfer - %d",r)); + return(r); + }

This function performs any configurations of the audio +hardware device that were deferred from the DSoundScPdd::SetConfig() function. +These configurations may include start-up of the DMA engine, enabling any +interrupts related to audio transfer and interrupts that detect error conditions, +for example. At this stage, no data has yet been supplied to the device for +transfer as the function DSoundScPdd::TransferData() has +not yet been called.

If the PDD supports both record and playback +driver channels then it may be necessary to ensure that such hardware configuration +on one channel cannot interfere with the other.

+
TransferData()

Implement +the DSoundScPdd::TransferData function for both playback +and record driver channels. This has the following signature:

TInt DSoundScPdd::TransferData(TUint aTransferID,TLinAddr aLinAddr, + TPhysAddr aPhysAddr,TInt aNumBytes)

Once +transfer has been started by calling DSoundScPdd::StartTransfer(), +the function TransferData is called repeatedly by the LDD +for the transfer of each fragment. See the playback and record sections for +details.

The template version for the record driver channel contains +the following code:

TInt DTemplateSoundScRxPdd::TransferData(TUint aTransferID, TLinAddr aLinAddr, + TPhysAddr /*aPhysAddr*/, TInt aNumBytes) + { + TInt r=KErrNone; + + // Check that we can accept the request + if (iPendingRecord>=KTemplateMaxRxDmaRequests) + r=KErrNotReady; + else + { + // Start a DMA transfer. + iDmaRequest[iFlag]->iTransferID=aTransferID; + iDmaRequest[iFlag]->iTransferSize=aNumBytes; + // TO DO: (mandatory) + // Supply the DMA source information. + TUint32 src=0; // ??? + r=iDmaRequest[iFlag]->Fragment(src,aLinAddr,aNumBytes,KDmaMemDest|KDmaIncDest,0); + if (r==KErrNone) + { + iDmaRequest[iFlag]->Queue(); + iPendingRecord++; + if ((++iFlag)>=KTemplateMaxRxDmaRequests) + iFlag=0; + + // TO DO: (mandatory) + // Start the audio device transferring data. + } + } + + return(r); + }

The template version used by the playback function +is very similar.

The first step is for the PDD to check that +it has the capacity to accept a further transfer. For example, check that +the PDD has a DMA request object that is free and that the DMA controller +has the capacity for another transfer to be queued. If the PDD does not have +the capacity to accept another transfer then it should immediately return KErrNotReady to +signal this.

Otherwise, the PDD can start a DMA transfer. To do this +it must acquire a DMA request object. The class DTemplateSoundScRxDmaRequest is +the abstraction for a DMA record request and is defined as follows:

/** Wrapper function for a shared chunk sound driver record DMA request. */ +class DTemplateSoundScRxDmaRequest : public DDmaRequest + { +public: + DTemplateSoundScRxDmaRequest(TDmaChannel& aChannel, DTemplateSoundScRxPdd* aPdd, + TInt aMaxTransferSize=0); + static void DmaService(TResult aResult, TAny* aArg); +public: + /** Pointer back to the PDD. */ + DTemplateSoundScRxPdd* iPdd; + /** The transfer ID for this DMA request - supplied by the LDD. */ + TUint iTransferID; + /** The transfer sizes in progress. */ + TUint iTransferSize; + }; + This is derived from DDmaRequest the base class + for a DMA request.

The data member iPdd is +a pointer to the owning PDD object. This is used within the member function DmaService() which +is the DMA callback function, and is called when the DMA request has been +completed by the DMA framework. The data member iTransferID is +a value supplied by the LDD which it uses to identify the transfer fragment. +The PDD must save this value and pass it back to the LDD when the transfer +is completed. Similarly, the member iTransferSize is used +to hold the length of the transfer fragment in bytes. If the transfer is successful +then this value is also passed back to the LDD to allow it to maintain its +count of bytes recorded.

The record PDD class owns an array of DMA +request objects:

/** The DMA request structures used for transfers. */ +DTemplateSoundScRxDmaRequest* iDmaRequest[KTemplateMaxRxDmaRequests];

It +also owns the data member iFlag, which always holds the number +for the next DMA request that should be used for transfer. Before starting +the DMA transfer, setup the appropriate DMA request object with the transfer +ID and the transfer length.

/** A flag selecting the next DMA request for transfer. */ +TInt iFlag;

Next the function DDmaRequest::Fragment() is +called to specify the details of the transfer to the DMA framework and to +allow it to analyse this. Here the appropriate platform specific 32-bit DMA +source identifier, src, needs to be supplied. The template +driver shown previously specifies the destination memory address as a linear +address but the physical address may be used instead. Both forms of this address +are passed as arguments to the TransferData() function.

If +fragmentation is successful then the request object is queued on the DMA channel DDmaRequest::Queue() and +the value of iFlag is updated ready for the next transfer. +The PDD class also keeps a count of the number of transfer fragments outstanding +by incrementing the variable iPendingRecord:

/** The number of outstanding DMA record requests on the DMA channel. */ +TInt iPendingRecord;

The final part of this function requires +platform specific code to start the audio hardware device transferring data. +This needs to be executed for each fragment transferred or just for the first +fragment queued following the StartTransfer() function.

Once +the transfer is complete, either successfully or with an error, the DMA framework +executes the static DMA callback function, DTemplateSoundScRxDmaRequest::DmaService(), +as follows:

/** +DMA rx service routine. Called in the sound thread's DFC context by the s/w DMA controller. +@param aResult Status of DMA transfer. +@param aArg Argument passed to DMA controller. +*/ +void DTemplateSoundScRxDmaRequest::DmaService(TResult aResult, TAny* aArg) + { + DTemplateSoundScRxDmaRequest& req=*(DTemplateSoundScRxDmaRequest*)aArg; + + TInt res=KErrNone; + TInt bytesTransferred=req.iTransferSize; + if (aResult!=DDmaRequest::EOk) + { + res=KErrCorrupt; + bytesTransferred=0; + } + + // Inform the LDD of the result of the transfer. + req.iPdd->RecordCallback(req.iTransferID,res,bytesTransferred); + return; + }

This function receives two arguments:

    +
  • the result of the transfer +from the DMA framework

  • +
  • an argument supplied +to the DMA framework when the request object was created

  • +

In this specific case, the argument type is a pointer to the DMA +request object, and allows the retrieval of the transfer ID and the transfer +size. In the template driver version an unsuccessful transfer returns an error +value of KErrCorrupt with a transfer byte count of zero.

From +the callback function we call the record PDD function to decrement the count +of transfer fragments outstanding and to inform the LDD of the completion +of transfer.

void DTemplateSoundScRxPdd::RecordCallback(TUint aTransferID, TInt aTransferResult,TInt aBytesTransferred) + { + iPendingRecord--; + Ldd()->RecordCallback(aTransferID,aTransferResult,aBytesTransferred); + } +
+
StopTransfer()

Implement +the DSoundScPdd::StopTransfer function for both the play +and record driver channels. This has the following signature:

void DSoundScPdd::StopTransfer()

The +PDD must reverse any operation performed on the audio hardware device done +as part of StartTransfer() or TransferData(). +This includes stopping the audio hardware device from transferring data and +stopping the DMA channel.

The template version for the record driver +channel contains the following code:

void DTemplateSoundScRxPdd::StopTransfer() + { + // Stop the DMA channel. + iDmaChannel->CancelAll(); + iFlag=0; + iPendingRecord=0; + + // TO DO: (mandatory) + // Stop the audio device transferring data. + }

The version used by the playback function is +very similar.

+
PauseTransfer()

Implement +the DSoundScPdd::PauseTransfer() function for both the +playback and record driver channels. This has the following signature:

TInt DSoundScPdd::PauseTransfer()

When +pausing playback, there is normally some way to temporarily stop the codec +and pause the DMA channel so that it can be resumed later starting from the +next play sample.

Pausing record requires a different implementation. +All active transfers must be aborted. When this has been achieved, the PDD +must report back to the LDD how much data has been received for the fragment +that was actively being transferred when the abort took place by calling DSoundScLdd::RecordCallBack(). +If it is not possible to determine the byte count for the last fragment from +the DMA controller, then you must find some other way to discover its value. +One solution is to re-start a timer at the start of each record fragment, +and use this to calculate how much data will have been written into the record +buffer at the point the transfer is aborted.

In this case the +returned transfer ID is not important.

The supplied template +implementation is as follows:

TInt DTemplateSoundScRxPdd::PauseTransfer() + { + // Stop the DMA channel. + iDmaChannel->CancelAll(); + + if (iPendingRecord) + { + // TO DO: (mandatory) + // Determine how much data was successfully transferred to the + // record buffer before transfer was aborted. + TInt byteCount=0; // ??? + Ldd()->RecordCallback(0,KErrNone,byteCount); + iPendingRecord=0; + } + iFlag=0; + + // TO DO: (mandatory) + // Halt recording on the audio device. + TInt r=KErrNone; + + return(r); + } +

There is no need for the PDD to perform any state +checking as this is already performed by the LDD. For example, checking that +the device is not already paused or transferring data.

+
ResumeTransfer()

Implement +the DSoundScPdd::ResumeTransfer function for both the playback +and record driver channels. This has the following signature:

TInt DSoundScPdd::ResumeTransfer()

The +template version for the record driver channel contains the following code:

TInt DTemplateSoundScTxPdd::ResumeTransfer() + { + __KTRACE_SND(Kern::Printf(">DTemplateSoundScTxPdd::ResumeTransfer")); + + // TO DO: (mandatory) + // Resume playback on the audio device. + TInt r=KErrNone; + + return(r); + }

To resume playback, it is normally necessary to re-start +the codec and resume the DMA channel in order to restart playback from the +next play sample.

To resume record, all active transfers should have +been aborted when the device was paused with the function PauseTransfer(). +However, the LDD issues a new TransferData() request subsequent +to this function to resume record data transfer so the only action required +here is to recreate the same audio hardware setup that was achieved in response +to the StartTransfer() function.

There is no need +for the PDD to perform any state checking as this is already performed by +the LDD. For example, checking that the device is not already paused.

+
PowerDown()

Implement +the DSoundScPdd::PowerDown() function for both the playback +and record driver channels. This has the following signature:

void DSoundScPdd::PowerDown()

The +PDD must reverse any operation performed on the audio hardware as part of PowerUp().

+
CustomConfig()

Implement +the DSoundScPdd::CustomConfig() function for both the playback +and record driver channels. This has the following signature:

TInt DSoundScPdd::CustomConfig(TInt aFunction,TAny* aParam)

RSoundSc::CustomConfig() is called by the LDD in response to a custom configuration request by the +client. Custom configurations allow clients to issue requests to setup platform +specific audio configuration settings. Any such requests from the client with +a function identifier equal to or above 0x10000000 are passed straight through +to the PDD for function identification and implementation. These are handled +in the context of the sound driver DFC thread.

If custom configuration +is not supported, then the PDD should simply return KErrNotSupported.

+
\ No newline at end of file