diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-4AEF7595-17C0-513E-9568-B212E6194388.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-4AEF7595-17C0-513E-9568-B212E6194388.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,163 @@ + + + + + +Record +operationDescribes the operation of the Sound Driver for sound recording. +
Client functions

Many aspects regarding the way +that the Sound Driver recording operates are similar to the way it handles +playback. One difference is how the memory location in the Shared +Chunks for the transfer is determined. In play requests, the client +specifies the source location in the chunk for the transfer having arranged +for the data to be loaded there prior to the request. For record requests, +the client just requests a buffers worth of record data and allows the driver +to decide which buffer to use for the request.

The driver commences +recording when the client issues the first RSoundSc::RecordData() request. +However, unlike playback operation, once recording has commenced, the driver +continues to record data into its available record buffers until it is told +to stop. To stop the driver capturing record data, the client must either +issue RSoundSc::Pause() to temporarily suspend recording, RSoundSc::CancelRecordData() to +terminate record operation, or close the driver channel altogether.

The +client specifies the number and size of the record buffers available to the +driver within the shared chunk by calling either RSoundSc::SetBufferChunkCreate(), +to create a buffer, or RSoundSc::SetBufferChunkOpen() to +open an existing buffer.

When the driver starts recording, all the +buffers in the shared chunk are empty, and the driver can use all of these +available buffers. They are filled one by one, and if the client is slow to +request the recorded data, then once the driver has filled all of the available +empty buffers, it is forced to discard the earliest one filled and re-use +this to continue recording data.

Each time the client requests a buffers +worth of recorded data with RSoundSc::RecordData(), it +is given the earliest one filled. This buffer is now said to be in-use and +unavailable to the driver for capturing. This buffer remains in-use until +it is freed by the client with a call of RSoundSc::ReleaseBuffer().

When +buffers are in use by the client the number of buffers available to the driver +for capture is reduced. If the client is slow to release buffers and the number +of available buffers falls to two then further RSoundSc::RecordData() requests +fail with KErrInUse until the client has freed some buffers. +The driver always needs a working set of at least two buffers in order to +achieve uninterrupted data capture. The driver always has a current buffer +which is actively being filled and another queued in advance. If the client +fails to take buffers at full speed then they are discarded by the driver.

The +driver does not slow down if it runs out of empty buffers.

Buffers

The driver maintains three buffer lists:

    +
  • free list

  • +
  • completed list

  • +
  • in-use list.

  • +

A record buffer can only exist in one of these lists at any time. +The free list contains buffers that are empty and not in use by the client. +Once a buffer has been filled with record data it is moved into the completed +buffer list. Here the buffer remains until it is passed back to the client +in response to a record request. When a client is using the buffer it is deemed +as in-use and is moved to the in-use list. Each time the client successfully +calls RSoundSc::ReleaseBuffer() to free up a buffer then +the driver moves this from the in-use list to the free list.

The driver +also maintains two record buffers which are excluded from any of the three +lists.

    +
  • the current buffer, +the one actively being filled with record data

  • +
  • the next buffer which +becomes the active buffer once the current buffer is filled

  • +

During recording there may be DMA requests pending for both the current +buffer and the next buffers.

+ The record buffer cycle +

The numbers one to five show the buffer cycle under normal operation, +while the letters A to C show error induced operation.

+ +

When recording commences, the driver removes two buffers from the +free list making one the current buffer and the other the next buffer (4 and +5).

When the current buffer is set as filled, the LDD normally adds +this to the completed list (1). If a record error has occurred while recording +to this buffer and it is only partially filled, or even empty then the buffer +is still added to the completed list, as the client needs to be informed of +the error (1). The only exception is in handling record pause, where a record +buffer ends up being completed with no error and with no data added. In this +case the buffer is added straight into the free list (A).

Having added +the current buffer to one of these lists, the driver moves the next buffer +to the current buffer (5) and then obtains a new next buffer (4). In normal +operation this comes from the free list but if the client is slow, this list +may be empty and the buffer is taken from the completed list (B). This is +a buffer overflow situation which is reported to the client as a response +to its next RSoundSc::RecordData() request as KErrOverFlow.

Whenever +a buffer is filled, the driver checks if there is a record request pending +(1). Similarly, when the driver processes a new record request it checks if +a filled buffer is already available. In either case, if a request can be +completed to the client then the earliest buffer completed is returned. If +this buffer was filled successfully then it added to the in-use list (2). +However, if an error occurred whilst filling the buffer then it is returned +straight to the free list instead (C).

Each time the client successfully +calls RSoundSc::ReleaseBuffer() to free up a buffer then +the driver moves this from the in-use list to the free list (3).

+
Audio recording

RecordData()

If +the driver is not already recording data then the first RSoundSc::RecordData() request +is handled in the context of the driver DFC thread, as access to the audio +hardware is required to enable record operation. However, for efficiency, +subsequent record requests from the client are handled entirely in the context +of the calling thread, as access to the audio hardware is not required to +handle the request. The driver only has to check whether there is a filled +record buffer already available. If there is then the driver completes the +request straight away. If not, the driver saves the details of the request +until a filled buffer does become available.

Returning to the case +of a record request where the driver is not already in the process of recording +data, the LDD first checks whether the client has specified or supplied a +shared chunk to the driver channel and has set the audio configuration and +record level. If the buffer configuration has not been specified then the +driver cannot proceed and returns KErrNotReady. If the audio +configuration or record level has not been specified then the LDD applies +default settings to the audio hardware device for each instead by calling +the functions DSoundSc::SetConfig() and DSoundScPdd::SetVolume() on +the PDD.

StartTransfer()

Depending +on the mapping attributes of the shared chunk, the LDD may now need to purge +the region of the record chunk concerned. Next the LDD calls DSoundScPdd::StartTransfer() on +the PDD to allow it to prepare the audio hardware device for record data transfer.

TransferData()

The LDD may need to break down the record buffer +into memory fragments. These specify a physically contiguous region and are +manageable by the PDD as a single transfer. The LDD queues as many transfer +fragments of the current buffer on the PDD as it can accept with a call to DSoundScPdd::TransferData() for +each fragment. If all fragments from the current buffer are accepted by the +PDD then the LDD tries to queue fragments from the next buffer. As with playback, +to support uninterrupted transfer of audio data the PDD must be able to accept +multiple fragments simultaneously. As long as the LDD has transfer fragments +still to queue, it continues to call DSoundScPdd::TransferData() until +the PDD signals that it has temporarily reached its capacity by returning KErrNotReady.

RecordCallBack()

Each time the PDD completes the transfer +of a fragment from a record buffer, it must signal this event back to the +LDD by calling the function DSoundScLdd::RecordCallBack(). +This must always be called in the context of the driver DFC thread. In executing DSoundScLdd::RecordCallback(), +the LDD checks whether the entire transfer for the current buffer is now complete. +If so, depending on the mapping attributes of the shared chunk, the LDD may +need to purge the region of the record client. The LDD attempts to queue further +fragments on the PDD, by calling DSoundScPdd::TransferData(), +which should now have the capability to accept more transfers. So, the PDD +should be written to handle calls to DSoundScPdd::TransferData() within +its call back to DSoundScLdd::RecordCallback().

+
Pause and resume audio recording

The client can +temporarily halt the progress of audio record at any time by issuing DSoundScLdd::Pause(). +To configure the audio hardware device to halt recording, the LDD calls DSoundScPdd::PauseTransfer() on +the PDD. This time, any active transfer should be aborted by the PDD. If a +recording is halted the PDD must signal this event with a single call of the +LDD function DSOundScLdd::RecordCallback(), which reports +back any partial data already received. In this case, if transfer is resumed +later, the LDD issues a new DSoundScPdd::TransferData() request +to commence data transfer after calling DSoundScPdd::ResumeTransfer(). +As access to the hardware is required in both cases, pause and resume are +handled in the context of the driver DFC thread.

+
Error handling during recording

If the PDD reports +an error when setting up the audio hardware device for recording then the +LDD immediately completes the first record request back to the client returning +the error value as the result. It will not restart record data transfer unless +it receives a further record request from the client.

If the PDD reports +an error when commencing the transfer of a record fragment or as the result +of the transfer of a record fragment, then the LDD ceases transfer to that +record buffer and instead reports the error back to the client. The error +is returned in response to the record request which corresponds with that +buffer.

Unexpected errors from the PDD are returned to the LDD via +the functions DSoundScPdd::TransferData() and DSoundScLdd::RecordCallback().

The +LDD does not try to cancel the transfer of other fragments for the same buffer +that are already queued on the PDD, but it ignores their outcome. However, +the LDD does try to carry on with the transfer to other available record buffers.

+
\ No newline at end of file