|
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-4AEF7595-17C0-513E-9568-B212E6194388" xml:lang="en"><title>Record |
|
13 operation</title><shortdesc>Describes the operation of the Sound Driver for sound recording.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <section id="GUID-0722033C-4BC0-45D0-B980-C1FC680BBF70"><title>Client functions</title> <p>Many aspects regarding the way |
|
15 that the Sound Driver recording operates are similar to the way it handles |
|
16 playback. One difference is how the memory location in the <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita">Shared |
|
17 Chunks</xref> for the transfer is determined. In play requests, the client |
|
18 specifies the source location in the chunk for the transfer having arranged |
|
19 for the data to be loaded there prior to the request. For record requests, |
|
20 the client just requests a buffers worth of record data and allows the driver |
|
21 to decide which buffer to use for the request. </p> <p>The driver commences |
|
22 recording when the client issues the first <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-D96D7433-6CB5-3368-8B51-C19731C474AF"><apiname>RSoundSc::RecordData()</apiname></xref> request. |
|
23 However, unlike playback operation, once recording has commenced, the driver |
|
24 continues to record data into its available record buffers until it is told |
|
25 to stop. To stop the driver capturing record data, the client must either |
|
26 issue <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-16C40CF6-C84D-3901-8527-EA66842E0AAC"><apiname>RSoundSc::Pause()</apiname></xref> to temporarily suspend recording, <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-4B53ED55-EC95-35B3-B9D6-A24EF70D81F9"><apiname>RSoundSc::CancelRecordData()</apiname></xref> to |
|
27 terminate record operation, or close the driver channel altogether. </p> <p>The |
|
28 client specifies the number and size of the record buffers available to the |
|
29 driver within the shared chunk by calling either <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-1978D84C-6E2A-39C0-AF5F-17C85E5B25B4"><apiname>RSoundSc::SetBufferChunkCreate()</apiname></xref>, |
|
30 to create a buffer, or <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-46096E39-A530-3644-91F0-0B97AC3C6580"><apiname>RSoundSc::SetBufferChunkOpen()</apiname></xref> to |
|
31 open an existing buffer. </p> <p>When the driver starts recording, all the |
|
32 buffers in the shared chunk are empty, and the driver can use all of these |
|
33 available buffers. They are filled one by one, and if the client is slow to |
|
34 request the recorded data, then once the driver has filled all of the available |
|
35 empty buffers, it is forced to discard the earliest one filled and re-use |
|
36 this to continue recording data. </p> <p>Each time the client requests a buffers |
|
37 worth of recorded data with <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-D96D7433-6CB5-3368-8B51-C19731C474AF"><apiname>RSoundSc::RecordData()</apiname></xref>, it |
|
38 is given the earliest one filled. This buffer is now said to be in-use and |
|
39 unavailable to the driver for capturing. This buffer remains in-use until |
|
40 it is freed by the client with a call of <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-26F7C97B-D06A-32BE-90B3-2E6918BF3F4D"><apiname>RSoundSc::ReleaseBuffer()</apiname></xref>. </p> <p>When |
|
41 buffers are in use by the client the number of buffers available to the driver |
|
42 for capture is reduced. If the client is slow to release buffers and the number |
|
43 of available buffers falls to two then further <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-D96D7433-6CB5-3368-8B51-C19731C474AF"><apiname>RSoundSc::RecordData()</apiname></xref> requests |
|
44 fail with <codeph>KErrInUse</codeph> until the client has freed some buffers. |
|
45 The driver always needs a working set of at least two buffers in order to |
|
46 achieve uninterrupted data capture. The driver always has a current buffer |
|
47 which is actively being filled and another queued in advance. If the client |
|
48 fails to take buffers at full speed then they are discarded by the driver. </p><p><note> The |
|
49 driver does not slow down if it runs out of empty buffers. </note></p> <p><b>Buffers</b> </p> <p>The driver maintains three buffer lists: </p> <ul> |
|
50 <li id="GUID-D0B884B5-3687-5CB9-B732-1B028F0008A8"><p>free list </p> </li> |
|
51 <li id="GUID-3A3FAAA7-72C2-5A35-9F4D-3824966D3D52"><p>completed list </p> </li> |
|
52 <li id="GUID-E571D299-99C5-51D1-832E-55A88533B365"><p>in-use list. </p> </li> |
|
53 </ul> <p>A record buffer can only exist in one of these lists at any time. |
|
54 The free list contains buffers that are empty and not in use by the client. |
|
55 Once a buffer has been filled with record data it is moved into the completed |
|
56 buffer list. Here the buffer remains until it is passed back to the client |
|
57 in response to a record request. When a client is using the buffer it is deemed |
|
58 as in-use and is moved to the <i>in-use</i> list. Each time the client successfully |
|
59 calls <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-26F7C97B-D06A-32BE-90B3-2E6918BF3F4D"><apiname>RSoundSc::ReleaseBuffer()</apiname></xref> to free up a buffer then |
|
60 the driver moves this from the in-use list to the free list. </p> <p>The driver |
|
61 also maintains two record buffers which are excluded from any of the three |
|
62 lists. </p> <ul> |
|
63 <li id="GUID-3EB509DB-F35F-51E7-AAD9-8A25EEDAE604"><p>the current buffer, |
|
64 the one actively being filled with record data </p> </li> |
|
65 <li id="GUID-E109F4E5-998D-5B19-AE82-A913BBF4CED3"><p>the next buffer which |
|
66 becomes the active buffer once the current buffer is filled </p> </li> |
|
67 </ul> <p>During recording there may be DMA requests pending for both the current |
|
68 buffer and the next buffers. </p> <fig id="GUID-FBF47E94-8334-55D3-9AC0-FDAF1F9960B1"> |
|
69 <title> The record buffer cycle </title> |
|
70 <desc><p>The numbers one to five show the buffer cycle under normal operation, |
|
71 while the letters A to C show error induced operation. </p> </desc> |
|
72 <image href="GUID-1A92047A-3C1D-5B4C-949B-98D770F5F530_d0e398658_href.png" placement="inline"/> |
|
73 </fig> <p>When recording commences, the driver removes two buffers from the |
|
74 free list making one the current buffer and the other the next buffer (4 and |
|
75 5). </p> <p>When the current buffer is set as filled, the LDD normally adds |
|
76 this to the completed list (1). If a record error has occurred while recording |
|
77 to this buffer and it is only partially filled, or even empty then the buffer |
|
78 is still added to the completed list, as the client needs to be informed of |
|
79 the error (1). The only exception is in handling record pause, where a record |
|
80 buffer ends up being completed with no error and with no data added. In this |
|
81 case the buffer is added straight into the free list (A). </p> <p>Having added |
|
82 the current buffer to one of these lists, the driver moves the next buffer |
|
83 to the current buffer (5) and then obtains a new next buffer (4). In normal |
|
84 operation this comes from the free list but if the client is slow, this list |
|
85 may be empty and the buffer is taken from the completed list (B). This is |
|
86 a buffer overflow situation which is reported to the client as a response |
|
87 to its next <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-D96D7433-6CB5-3368-8B51-C19731C474AF"><apiname>RSoundSc::RecordData()</apiname></xref> request as <codeph>KErrOverFlow</codeph>. </p> <p>Whenever |
|
88 a buffer is filled, the driver checks if there is a record request pending |
|
89 (1). Similarly, when the driver processes a new record request it checks if |
|
90 a filled buffer is already available. In either case, if a request can be |
|
91 completed to the client then the earliest buffer completed is returned. If |
|
92 this buffer was filled successfully then it added to the in-use list (2). |
|
93 However, if an error occurred whilst filling the buffer then it is returned |
|
94 straight to the free list instead (C). </p> <p>Each time the client successfully |
|
95 calls <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-26F7C97B-D06A-32BE-90B3-2E6918BF3F4D"><apiname>RSoundSc::ReleaseBuffer()</apiname></xref> to free up a buffer then |
|
96 the driver moves this from the in-use list to the free list (3). </p> </section> |
|
97 <section id="GUID-548515F6-403D-4C99-AAA3-027C7D303C73"><title>Audio recording</title> <p><b>RecordData()</b> </p> <p>If |
|
98 the driver is not already recording data then the first <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-D96D7433-6CB5-3368-8B51-C19731C474AF"><apiname>RSoundSc::RecordData()</apiname></xref> request |
|
99 is handled in the context of the driver DFC thread, as access to the audio |
|
100 hardware is required to enable record operation. However, for efficiency, |
|
101 subsequent record requests from the client are handled entirely in the context |
|
102 of the calling thread, as access to the audio hardware is not required to |
|
103 handle the request. The driver only has to check whether there is a filled |
|
104 record buffer already available. If there is then the driver completes the |
|
105 request straight away. If not, the driver saves the details of the request |
|
106 until a filled buffer does become available. </p> <p>Returning to the case |
|
107 of a record request where the driver is not already in the process of recording |
|
108 data, the LDD first checks whether the client has specified or supplied a |
|
109 shared chunk to the driver channel and has set the audio configuration and |
|
110 record level. If the buffer configuration has not been specified then the |
|
111 driver cannot proceed and returns <codeph>KErrNotReady</codeph>. If the audio |
|
112 configuration or record level has not been specified then the LDD applies |
|
113 default settings to the audio hardware device for each instead by calling |
|
114 the functions <xref href="GUID-E1C67F8D-1A83-36B3-A451-22F496A659C6.dita#GUID-E1C67F8D-1A83-36B3-A451-22F496A659C6/GUID-23CEDA72-E161-30C4-B8D7-DBDCBC5B9C63"><apiname>DSoundSc::SetConfig()</apiname></xref> and <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-D893A29B-1A4B-35AF-876B-84D74B7E783C"><apiname>DSoundScPdd::SetVolume()</apiname></xref> on |
|
115 the PDD. </p> <p><b>StartTransfer()</b> </p> <p>Depending |
|
116 on the mapping attributes of the shared chunk, the LDD may now need to purge |
|
117 the region of the record chunk concerned. Next the LDD calls <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-54D3CC19-0C00-3FFA-BD1A-62618D36EB20"><apiname>DSoundScPdd::StartTransfer()</apiname></xref> on |
|
118 the PDD to allow it to prepare the audio hardware device for record data transfer. </p> <p><b>TransferData()</b> </p> <p>The LDD may need to break down the record buffer |
|
119 into memory fragments. These specify a physically contiguous region and are |
|
120 manageable by the PDD as a single transfer. The LDD queues as many transfer |
|
121 fragments of the current buffer on the PDD as it can accept with a call to <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-8C79D09B-317A-3D8E-B9C2-474812F17529"><apiname>DSoundScPdd::TransferData()</apiname></xref> for |
|
122 each fragment. If all fragments from the current buffer are accepted by the |
|
123 PDD then the LDD tries to queue fragments from the next buffer. As with playback, |
|
124 to support uninterrupted transfer of audio data the PDD must be able to accept |
|
125 multiple fragments simultaneously. As long as the LDD has transfer fragments |
|
126 still to queue, it continues to call <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-8C79D09B-317A-3D8E-B9C2-474812F17529"><apiname>DSoundScPdd::TransferData()</apiname></xref> until |
|
127 the PDD signals that it has temporarily reached its capacity by returning <codeph>KErrNotReady</codeph>. </p> <p><b>RecordCallBack()</b> </p> <p>Each time the PDD completes the transfer |
|
128 of a fragment from a record buffer, it must signal this event back to the |
|
129 LDD by calling the function <xref href="GUID-5807543D-A30F-3EB9-8F28-91A623B0D484.dita#GUID-5807543D-A30F-3EB9-8F28-91A623B0D484/GUID-9112E399-DC3C-334F-BE16-B5F42216F903"><apiname>DSoundScLdd::RecordCallBack()</apiname></xref>. |
|
130 This must always be called in the context of the driver DFC thread. In executing <xref href="GUID-5807543D-A30F-3EB9-8F28-91A623B0D484.dita#GUID-5807543D-A30F-3EB9-8F28-91A623B0D484/GUID-434E378F-0C48-39D9-8FB8-9831A1F704C0"><apiname>DSoundScLdd::RecordCallback()</apiname></xref>, |
|
131 the LDD checks whether the entire transfer for the current buffer is now complete. |
|
132 If so, depending on the mapping attributes of the shared chunk, the LDD may |
|
133 need to purge the region of the record client. The LDD attempts to queue further |
|
134 fragments on the PDD, by calling <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-8C79D09B-317A-3D8E-B9C2-474812F17529"><apiname>DSoundScPdd::TransferData()</apiname></xref>, |
|
135 which should now have the capability to accept more transfers. So, the PDD |
|
136 should be written to handle calls to <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-8C79D09B-317A-3D8E-B9C2-474812F17529"><apiname>DSoundScPdd::TransferData()</apiname></xref> within |
|
137 its call back to <xref href="GUID-5807543D-A30F-3EB9-8F28-91A623B0D484.dita#GUID-5807543D-A30F-3EB9-8F28-91A623B0D484/GUID-434E378F-0C48-39D9-8FB8-9831A1F704C0"><apiname>DSoundScLdd::RecordCallback()</apiname></xref>. </p> </section> |
|
138 <section id="GUID-7B5CF9A4-8527-4C76-96CD-C03F861AF3BF"><title>Pause and resume audio recording</title> <p>The client can |
|
139 temporarily halt the progress of audio record at any time by issuing <xref href="GUID-5807543D-A30F-3EB9-8F28-91A623B0D484.dita#GUID-5807543D-A30F-3EB9-8F28-91A623B0D484/GUID-D912620F-9C51-3AFC-8A59-31AF9455AC4A"><apiname>DSoundScLdd::Pause()</apiname></xref>. |
|
140 To configure the audio hardware device to halt recording, the LDD calls <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-0608766F-2645-3E28-B804-BD4B953DB5FF"><apiname>DSoundScPdd::PauseTransfer()</apiname></xref> on |
|
141 the PDD. This time, any active transfer should be aborted by the PDD. If a |
|
142 recording is halted the PDD must signal this event with a single call of the |
|
143 LDD function <xref href="GUID-3731902C-9C34-3FAE-8F82-9F9493C2C2E7.dita#GUID-3731902C-9C34-3FAE-8F82-9F9493C2C2E7/GUID-73F74080-6219-3D9A-BA56-735A17A9ABA0"><apiname>DSOundScLdd::RecordCallback()</apiname></xref>, which reports |
|
144 back any partial data already received. In this case, if transfer is resumed |
|
145 later, the LDD issues a new <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-8C79D09B-317A-3D8E-B9C2-474812F17529"><apiname>DSoundScPdd::TransferData()</apiname></xref> request |
|
146 to commence data transfer after calling <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-C692BF61-FA3D-3B85-BCC6-1248C9C7D9BF"><apiname>DSoundScPdd::ResumeTransfer()</apiname></xref>. |
|
147 As access to the hardware is required in both cases, pause and resume are |
|
148 handled in the context of the driver DFC thread. </p> </section> |
|
149 <section id="GUID-BA951968-290F-4DA5-842A-2004664B1139"><title>Error handling during recording</title> <p>If the PDD reports |
|
150 an error when setting up the audio hardware device for recording then the |
|
151 LDD immediately completes the first record request back to the client returning |
|
152 the error value as the result. It will not restart record data transfer unless |
|
153 it receives a further record request from the client. </p> <p>If the PDD reports |
|
154 an error when commencing the transfer of a record fragment or as the result |
|
155 of the transfer of a record fragment, then the LDD ceases transfer to that |
|
156 record buffer and instead reports the error back to the client. The error |
|
157 is returned in response to the record request which corresponds with that |
|
158 buffer. </p> <p>Unexpected errors from the PDD are returned to the LDD via |
|
159 the functions <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-8C79D09B-317A-3D8E-B9C2-474812F17529"><apiname>DSoundScPdd::TransferData()</apiname></xref> and <xref href="GUID-5807543D-A30F-3EB9-8F28-91A623B0D484.dita#GUID-5807543D-A30F-3EB9-8F28-91A623B0D484/GUID-434E378F-0C48-39D9-8FB8-9831A1F704C0"><apiname>DSoundScLdd::RecordCallback()</apiname></xref>. </p> <p>The |
|
160 LDD does not try to cancel the transfer of other fragments for the same buffer |
|
161 that are already queued on the PDD, but it ignores their outcome. However, |
|
162 the LDD does try to carry on with the transfer to other available record buffers. </p> </section> |
|
163 </conbody></concept> |