sl@0
|
1 |
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
// source\server\mmfdatapath.cpp
|
sl@0
|
15 |
//
|
sl@0
|
16 |
//
|
sl@0
|
17 |
|
sl@0
|
18 |
#include <e32math.h>
|
sl@0
|
19 |
#include <mmf/common/mmffourcc.h>
|
sl@0
|
20 |
#include <mmf/common/mmfpaniccodes.h>
|
sl@0
|
21 |
#include <mmf/server/mmfaudiooutput.h>
|
sl@0
|
22 |
#include <mmf/server/mmfaudioinput.h>
|
sl@0
|
23 |
#include <mmf/server/mmfdatapath.h>
|
sl@0
|
24 |
#include "mmfclientaudiostreamutils.h"
|
sl@0
|
25 |
#include <mmf/common/mmfaudio.h>
|
sl@0
|
26 |
#include <mmf/plugin/mmfcodecimplementationuids.hrh> // KUidMmfCodecAudioSettings
|
sl@0
|
27 |
#include <mmf/server/devsoundstandardcustominterfaces.h>
|
sl@0
|
28 |
|
sl@0
|
29 |
const TUid KUidCodecAudioConfig = {KUidMmfCodecAudioSettings};
|
sl@0
|
30 |
|
sl@0
|
31 |
void Panic(TMMFDataPathPanicCode aPanicCode, TInt aSourceLineNumber)
|
sl@0
|
32 |
{
|
sl@0
|
33 |
_LIT(KMMFDataPathPanicCategory, "MMFDataPath");
|
sl@0
|
34 |
User::Panic(KMMFDataPathPanicCategory, STATIC_CAST(TInt,aPanicCode) + aSourceLineNumber);
|
sl@0
|
35 |
}
|
sl@0
|
36 |
|
sl@0
|
37 |
//all functions are exported form the DLL and are virtual to allow plugins to define there own CMMFDataPaths
|
sl@0
|
38 |
|
sl@0
|
39 |
/**
|
sl@0
|
40 |
Allocates and constructs a data path.
|
sl@0
|
41 |
|
sl@0
|
42 |
Use this function if the codec UID is not already known by CMMFController
|
sl@0
|
43 |
and there is no data path ambiguity - ie only one data path is possible.
|
sl@0
|
44 |
|
sl@0
|
45 |
Will create codec via fourCC.
|
sl@0
|
46 |
|
sl@0
|
47 |
@param aEventHandler
|
sl@0
|
48 |
Installs an event handler to provide message passing between clients and sources/sinks.
|
sl@0
|
49 |
|
sl@0
|
50 |
@return Newly constructed data path object.
|
sl@0
|
51 |
*/
|
sl@0
|
52 |
|
sl@0
|
53 |
EXPORT_C CMMFDataPath* CMMFDataPath::NewL(MAsyncEventHandler& aEventHandler)
|
sl@0
|
54 |
{
|
sl@0
|
55 |
CMMFDataPath* self = new(ELeave) CMMFDataPath(TMediaId(), aEventHandler);
|
sl@0
|
56 |
CleanupStack::PushL(self);
|
sl@0
|
57 |
self->ConstructL();
|
sl@0
|
58 |
CleanupStack::Pop();
|
sl@0
|
59 |
return self;
|
sl@0
|
60 |
}
|
sl@0
|
61 |
|
sl@0
|
62 |
|
sl@0
|
63 |
/**
|
sl@0
|
64 |
Allocates and constructs a data path according to the specified media ID.
|
sl@0
|
65 |
|
sl@0
|
66 |
Use this function if the codec UID is not already known by CMMFController
|
sl@0
|
67 |
and there is ambiguity with the data path ie. there is more than one possible data path.
|
sl@0
|
68 |
|
sl@0
|
69 |
@param aMediaId
|
sl@0
|
70 |
Optional media ID parameter when there are multiple media types.
|
sl@0
|
71 |
@param aEventHandler
|
sl@0
|
72 |
Installs an event handler to provide message passing between clients and sources/sinks.
|
sl@0
|
73 |
|
sl@0
|
74 |
@return A newly constructed data path object.
|
sl@0
|
75 |
*/
|
sl@0
|
76 |
|
sl@0
|
77 |
EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
|
sl@0
|
78 |
{
|
sl@0
|
79 |
CMMFDataPath* self = new(ELeave) CMMFDataPath(aMediaId, aEventHandler);
|
sl@0
|
80 |
CleanupStack::PushL(self);
|
sl@0
|
81 |
self->ConstructL();
|
sl@0
|
82 |
CleanupStack::Pop();
|
sl@0
|
83 |
return self;
|
sl@0
|
84 |
}
|
sl@0
|
85 |
|
sl@0
|
86 |
/**
|
sl@0
|
87 |
Allocates and constructs a data path according to the specified codec UID.
|
sl@0
|
88 |
|
sl@0
|
89 |
Use this function if the codec UID is already known by CMMFController
|
sl@0
|
90 |
and there is no data path ambiguity ie. only one data path is possible
|
sl@0
|
91 |
will create codec explicitly using the supplied codec Uid
|
sl@0
|
92 |
|
sl@0
|
93 |
@param aCodecUid
|
sl@0
|
94 |
Optional mediaID parameter when there are multiple media types
|
sl@0
|
95 |
@param aEventHandler
|
sl@0
|
96 |
Installs an event handler to provide message passing between clients and sources/sinks.
|
sl@0
|
97 |
|
sl@0
|
98 |
@return A newly constructed data path object.
|
sl@0
|
99 |
*/
|
sl@0
|
100 |
|
sl@0
|
101 |
EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TUid aCodecUid, MAsyncEventHandler& aEventHandler)
|
sl@0
|
102 |
{
|
sl@0
|
103 |
CMMFDataPath* self = new(ELeave) CMMFDataPath(TMediaId(), aEventHandler);
|
sl@0
|
104 |
CleanupStack::PushL(self);
|
sl@0
|
105 |
self->ConstructL(aCodecUid);
|
sl@0
|
106 |
CleanupStack::Pop();
|
sl@0
|
107 |
return self;
|
sl@0
|
108 |
}
|
sl@0
|
109 |
|
sl@0
|
110 |
|
sl@0
|
111 |
/**
|
sl@0
|
112 |
Allocates and constructs a data path according to the specified codec UID.
|
sl@0
|
113 |
|
sl@0
|
114 |
Use this function if the codec UID is already known by CMMFController
|
sl@0
|
115 |
and there is ambiguity ie. more than one possible data path.
|
sl@0
|
116 |
TMediaId used to select the path.
|
sl@0
|
117 |
|
sl@0
|
118 |
@param aCodecUid
|
sl@0
|
119 |
The codec UID.
|
sl@0
|
120 |
@param aMediaId
|
sl@0
|
121 |
Optional mediaID parameter when there are multiple media types.
|
sl@0
|
122 |
@param aEventHandler
|
sl@0
|
123 |
Installs an event handler to provide message passing between clients and sources/sinks.
|
sl@0
|
124 |
|
sl@0
|
125 |
@return A newly constructed data path object.
|
sl@0
|
126 |
*/
|
sl@0
|
127 |
EXPORT_C CMMFDataPath* CMMFDataPath::NewL(TUid aCodecUid, TMediaId aMediaId, MAsyncEventHandler& aEventHandler)
|
sl@0
|
128 |
{
|
sl@0
|
129 |
CMMFDataPath* self = new(ELeave) CMMFDataPath(aMediaId, aEventHandler);
|
sl@0
|
130 |
CleanupStack::PushL(self);
|
sl@0
|
131 |
self->ConstructL(aCodecUid);
|
sl@0
|
132 |
CleanupStack::Pop();
|
sl@0
|
133 |
return self;
|
sl@0
|
134 |
}
|
sl@0
|
135 |
|
sl@0
|
136 |
/**
|
sl@0
|
137 |
Standard destructor.
|
sl@0
|
138 |
*/
|
sl@0
|
139 |
|
sl@0
|
140 |
EXPORT_C CMMFDataPath::~CMMFDataPath()
|
sl@0
|
141 |
{
|
sl@0
|
142 |
Cancel();
|
sl@0
|
143 |
delete iCodec;
|
sl@0
|
144 |
DoCleanupBuffers();
|
sl@0
|
145 |
|
sl@0
|
146 |
//log off the source and sink
|
sl@0
|
147 |
if (iDataSource)
|
sl@0
|
148 |
iDataSource->SourceThreadLogoff();
|
sl@0
|
149 |
if (iDataSink)
|
sl@0
|
150 |
iDataSink->SinkThreadLogoff();
|
sl@0
|
151 |
|
sl@0
|
152 |
if (iCompleteCallback)
|
sl@0
|
153 |
{
|
sl@0
|
154 |
iCompleteCallback->Cancel();
|
sl@0
|
155 |
delete iCompleteCallback;
|
sl@0
|
156 |
}
|
sl@0
|
157 |
}
|
sl@0
|
158 |
|
sl@0
|
159 |
/**
|
sl@0
|
160 |
Deletes buffers if this datapath's sources and sinks own the buffers returned by PrimeL().
|
sl@0
|
161 |
Typically if buffers are created asychronously, the datapath doesn't own the buffer
|
sl@0
|
162 |
so leaves cleanup handling to the owner sources/sinks.
|
sl@0
|
163 |
|
sl@0
|
164 |
Called when source and sink needs to be de-referenced. Sets iDataPathCreated, iSinkCanReceive,
|
sl@0
|
165 |
iSnkBufRef and iSrcBufRef to EFalse; sets iState to EStopped.
|
sl@0
|
166 |
*/
|
sl@0
|
167 |
EXPORT_C void CMMFDataPath::ResetL()
|
sl@0
|
168 |
{
|
sl@0
|
169 |
delete iCodec;
|
sl@0
|
170 |
iCodec = NULL;
|
sl@0
|
171 |
DoCleanupBuffers(); // Delete buffers
|
sl@0
|
172 |
//logoff and dereference source and sink
|
sl@0
|
173 |
if (iDataSource)
|
sl@0
|
174 |
{ iDataSource->SourceThreadLogoff(); iDataSource = NULL; }
|
sl@0
|
175 |
if (iDataSink)
|
sl@0
|
176 |
{ iDataSink->SinkThreadLogoff(); iDataSink = NULL; }
|
sl@0
|
177 |
|
sl@0
|
178 |
// Reset states
|
sl@0
|
179 |
iDataPathCreated = EFalse;
|
sl@0
|
180 |
iState = EStopped;
|
sl@0
|
181 |
iSrcBufRef = EFalse;
|
sl@0
|
182 |
iSnkBufRef = EFalse;
|
sl@0
|
183 |
iPauseCalled = EFalse;
|
sl@0
|
184 |
|
sl@0
|
185 |
delete iCompleteCallback; iCompleteCallback = NULL;
|
sl@0
|
186 |
}
|
sl@0
|
187 |
|
sl@0
|
188 |
/**
|
sl@0
|
189 |
Delete source and/or sink buffers that are owned by DataPath.
|
sl@0
|
190 |
|
sl@0
|
191 |
Ownership indicated by iSrcBufRef and iSnkBufRef.
|
sl@0
|
192 |
|
sl@0
|
193 |
Ownership is assigned during buffer allocation within the datapath PrimeL().
|
sl@0
|
194 |
*/
|
sl@0
|
195 |
void CMMFDataPath::DoCleanupBuffers()
|
sl@0
|
196 |
{
|
sl@0
|
197 |
// delete source and/or sink buffer that is owned by DataPath
|
sl@0
|
198 |
if ( !iSrcBufRef && iSourceBuffer )
|
sl@0
|
199 |
{
|
sl@0
|
200 |
delete iSourceBuffer;
|
sl@0
|
201 |
}
|
sl@0
|
202 |
iSourceBuffer = NULL;
|
sl@0
|
203 |
if ( !iSnkBufRef && iSinkBuffer )
|
sl@0
|
204 |
{
|
sl@0
|
205 |
delete iSinkBuffer;
|
sl@0
|
206 |
}
|
sl@0
|
207 |
iSinkBuffer = NULL;
|
sl@0
|
208 |
}
|
sl@0
|
209 |
|
sl@0
|
210 |
|
sl@0
|
211 |
/**
|
sl@0
|
212 |
Obtain source and/or sink buffer using the synchronous API CreateSourceBufferL() and CreateSinkBufferL().
|
sl@0
|
213 |
*/
|
sl@0
|
214 |
void CMMFDataPath::ObtainSyncBuffersL()
|
sl@0
|
215 |
{
|
sl@0
|
216 |
//Try to create source and sink buffers. If we can't create them synchronously via
|
sl@0
|
217 |
//CreateSourceBufferL and CreateSinkBufferL we will need to obtain them by
|
sl@0
|
218 |
//asynchronous buffer creation when playing starts.
|
sl@0
|
219 |
|
sl@0
|
220 |
if (iBuffersToUse & ENeedSourceBuffer)
|
sl@0
|
221 |
{
|
sl@0
|
222 |
if (!iSourceBuffer) //we may already have a buffer from a previous initialization
|
sl@0
|
223 |
{
|
sl@0
|
224 |
TRAPD(err, iSourceBuffer = iDataSource->CreateSourceBufferL(iMediaId,*iSinkBuffer, iSrcBufRef));
|
sl@0
|
225 |
if(err != KErrNone && err != KErrNotSupported)
|
sl@0
|
226 |
{
|
sl@0
|
227 |
#ifdef _DP_DEBUG
|
sl@0
|
228 |
RDebug::Print(_L("DP::ObtainSyncBuffersL - Leaving %d (this 0x%x)\n"),err, this);
|
sl@0
|
229 |
#endif
|
sl@0
|
230 |
User::Leave(err);
|
sl@0
|
231 |
}
|
sl@0
|
232 |
}
|
sl@0
|
233 |
}
|
sl@0
|
234 |
|
sl@0
|
235 |
|
sl@0
|
236 |
if (iBuffersToUse & ENeedSinkBuffer)
|
sl@0
|
237 |
{
|
sl@0
|
238 |
if (!iSinkBuffer) //we may already have a buffer from a previous initialization
|
sl@0
|
239 |
{
|
sl@0
|
240 |
TRAPD(err, iSinkBuffer = iDataSink->CreateSinkBufferL(iMediaId, iSnkBufRef));
|
sl@0
|
241 |
if(err != KErrNone && err != KErrNotSupported)
|
sl@0
|
242 |
{
|
sl@0
|
243 |
#ifdef _DP_DEBUG
|
sl@0
|
244 |
RDebug::Print(_L("DP::ObtainSyncBuffersL - Leaving %d (this 0x%x)\n"),err, this);
|
sl@0
|
245 |
#endif
|
sl@0
|
246 |
User::Leave(err);
|
sl@0
|
247 |
}
|
sl@0
|
248 |
}
|
sl@0
|
249 |
}
|
sl@0
|
250 |
|
sl@0
|
251 |
if (iSourceBuffer && !(iBuffersToUse & ENeedSinkBuffer))
|
sl@0
|
252 |
{//only need one buffer, use source
|
sl@0
|
253 |
iSinkBuffer =iSourceBuffer;
|
sl@0
|
254 |
iSnkBufRef = ETrue; //the sink buffer is not to be deleted
|
sl@0
|
255 |
}
|
sl@0
|
256 |
else if (iSinkBuffer && !(iBuffersToUse & ENeedSourceBuffer))
|
sl@0
|
257 |
{//only need one buffer, use sink
|
sl@0
|
258 |
iSourceBuffer =iSinkBuffer;
|
sl@0
|
259 |
iSrcBufRef = ETrue; //the sink buffer is not to be deleted
|
sl@0
|
260 |
}
|
sl@0
|
261 |
|
sl@0
|
262 |
#ifdef _DP_DEBUG
|
sl@0
|
263 |
RDebug::Print(_L("DP::ObtainSyncBuffersL - DONE iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
264 |
#endif
|
sl@0
|
265 |
}
|
sl@0
|
266 |
|
sl@0
|
267 |
|
sl@0
|
268 |
|
sl@0
|
269 |
|
sl@0
|
270 |
|
sl@0
|
271 |
/**
|
sl@0
|
272 |
Constructs a source.
|
sl@0
|
273 |
|
sl@0
|
274 |
The default implementation leaves with KErrNotSupported.
|
sl@0
|
275 |
|
sl@0
|
276 |
@param aInitData
|
sl@0
|
277 |
The initialisation data.
|
sl@0
|
278 |
*/
|
sl@0
|
279 |
|
sl@0
|
280 |
EXPORT_C void CMMFDataPath::ConstructSourceL( const TDesC8& /*aInitData*/ )
|
sl@0
|
281 |
{
|
sl@0
|
282 |
User::Leave(KErrNotSupported);
|
sl@0
|
283 |
}
|
sl@0
|
284 |
|
sl@0
|
285 |
/**
|
sl@0
|
286 |
Constructs a sink.
|
sl@0
|
287 |
|
sl@0
|
288 |
Overridable constuction specific to this datasource.
|
sl@0
|
289 |
|
sl@0
|
290 |
The default implementation leaves with KErrNotSupported.
|
sl@0
|
291 |
|
sl@0
|
292 |
@param aInitData
|
sl@0
|
293 |
The initialisation data.
|
sl@0
|
294 |
*/
|
sl@0
|
295 |
EXPORT_C void CMMFDataPath::ConstructSinkL( const TDesC8& /*aInitData*/ )
|
sl@0
|
296 |
{
|
sl@0
|
297 |
User::Leave(KErrNotSupported);
|
sl@0
|
298 |
}
|
sl@0
|
299 |
|
sl@0
|
300 |
/**
|
sl@0
|
301 |
Takes UID of codec on construction, and if not an NULL codec sets the datapath up for codec instantiation.
|
sl@0
|
302 |
|
sl@0
|
303 |
@param aCodecUid
|
sl@0
|
304 |
The UID of the codec.
|
sl@0
|
305 |
*/
|
sl@0
|
306 |
|
sl@0
|
307 |
EXPORT_C void CMMFDataPath::ConstructL(TUid aCodecUid)
|
sl@0
|
308 |
{
|
sl@0
|
309 |
iUseSuppliedCodecUid = EFalse; //initially assume no supplied codec uid
|
sl@0
|
310 |
|
sl@0
|
311 |
if (aCodecUid != KNullUid)
|
sl@0
|
312 |
{//the data path NewL has specified a specific codec
|
sl@0
|
313 |
//create CMMFCodec here
|
sl@0
|
314 |
iCodec = CMMFCodec::NewL(aCodecUid);
|
sl@0
|
315 |
if (iCodec)
|
sl@0
|
316 |
iUseSuppliedCodecUid = ETrue;
|
sl@0
|
317 |
}
|
sl@0
|
318 |
|
sl@0
|
319 |
iSrcBufRef = EFalse;
|
sl@0
|
320 |
iSnkBufRef = EFalse;
|
sl@0
|
321 |
iObtainingAsyncSourceBuffer = EFalse;
|
sl@0
|
322 |
iObtainingAsyncSinkBuffer = EFalse;
|
sl@0
|
323 |
iSourceBufferWithSource = EFalse;
|
sl@0
|
324 |
iSinkBufferWithSink = EFalse;
|
sl@0
|
325 |
}
|
sl@0
|
326 |
|
sl@0
|
327 |
|
sl@0
|
328 |
/**
|
sl@0
|
329 |
Adds a data source to the datapath and, if the sink already exists, tries to establish a connection
|
sl@0
|
330 |
between the source and sink.
|
sl@0
|
331 |
|
sl@0
|
332 |
@param aSource
|
sl@0
|
333 |
The data source to add to the data path.
|
sl@0
|
334 |
*/
|
sl@0
|
335 |
EXPORT_C void CMMFDataPath::AddDataSourceL(MDataSource* aSource)
|
sl@0
|
336 |
{
|
sl@0
|
337 |
if (!iDataSink) iDataSource=aSource; //can't create a data path without the MDataSink as well
|
sl@0
|
338 |
else if (!iUseSuppliedCodecUid) //no supplied uid need to see if we can create codec to establish a data path
|
sl@0
|
339 |
{//we have a data sink as well so check a data path can be established between source&sink
|
sl@0
|
340 |
CreateDataPathL(aSource, iDataSink);
|
sl@0
|
341 |
iDataSource = aSource;
|
sl@0
|
342 |
}
|
sl@0
|
343 |
else //the CMMFController specified the codec uid so must use existing codec
|
sl@0
|
344 |
{//note we are assuming here that the CMMFController knows what it is doing ie the supplied codec uid
|
sl@0
|
345 |
//can make the appropriate data conversion
|
sl@0
|
346 |
iDataPathCreated = ETrue;
|
sl@0
|
347 |
iDataSource = aSource;
|
sl@0
|
348 |
}
|
sl@0
|
349 |
ClearPlayWindowL() ;
|
sl@0
|
350 |
User::LeaveIfError(iDataSource->SourceThreadLogon(*this));
|
sl@0
|
351 |
}
|
sl@0
|
352 |
|
sl@0
|
353 |
|
sl@0
|
354 |
/**
|
sl@0
|
355 |
Adds a data sink to the datapath and, if the source already exists, tries to establish a connection
|
sl@0
|
356 |
between the source and sink.
|
sl@0
|
357 |
|
sl@0
|
358 |
@param aSink
|
sl@0
|
359 |
The data sink to add to the data path.
|
sl@0
|
360 |
*/
|
sl@0
|
361 |
|
sl@0
|
362 |
EXPORT_C void CMMFDataPath::AddDataSinkL(MDataSink* aSink)
|
sl@0
|
363 |
{
|
sl@0
|
364 |
if (!iDataSource) iDataSink=aSink; //can't create a data path without the MDataSource as well
|
sl@0
|
365 |
else if (!iUseSuppliedCodecUid) //no supplied uid need to see if we can create codec to establish a data path
|
sl@0
|
366 |
{//we have a data source as well so check a media path can be established between source&sink
|
sl@0
|
367 |
CreateDataPathL(iDataSource, aSink);
|
sl@0
|
368 |
iDataSink = aSink;
|
sl@0
|
369 |
}
|
sl@0
|
370 |
else //the CMMFController specified the codec uid so must use existing codec
|
sl@0
|
371 |
{//note we are assuming here that the CMMFController knows what it is doing ie the supplied codec uid
|
sl@0
|
372 |
//can make the appropriate data conversion
|
sl@0
|
373 |
iDataPathCreated = ETrue;
|
sl@0
|
374 |
iDataSink = aSink;
|
sl@0
|
375 |
|
sl@0
|
376 |
//set 4CCs
|
sl@0
|
377 |
iSourceFourCC = iDataSink->SinkDataTypeCode(iMediaId);//sink because CMMFDataPath is an MDataSink to its MDataSource!
|
sl@0
|
378 |
iSinkFourCC = iDataSource->SourceDataTypeCode(iMediaId);//source because CMMFDataPath is an MDataSource to its MDataSink!
|
sl@0
|
379 |
}
|
sl@0
|
380 |
User::LeaveIfError(iDataSink->SinkThreadLogon(*this));
|
sl@0
|
381 |
}
|
sl@0
|
382 |
|
sl@0
|
383 |
|
sl@0
|
384 |
/*
|
sl@0
|
385 |
* CreateDataPathL
|
sl@0
|
386 |
*
|
sl@0
|
387 |
* internal function to establish a datapath between the source and sink
|
sl@0
|
388 |
* the data supplied by the sink adn expected by the source are checked and
|
sl@0
|
389 |
* a codec is instantiated if necessary
|
sl@0
|
390 |
*
|
sl@0
|
391 |
* @param aSource
|
sl@0
|
392 |
* @param aSink
|
sl@0
|
393 |
*/
|
sl@0
|
394 |
|
sl@0
|
395 |
void CMMFDataPath::CreateDataPathL(MDataSource* aSource, MDataSink* aSink)
|
sl@0
|
396 |
{ //procedure to attempt to match the source to the sink creating a codec if necessary
|
sl@0
|
397 |
// returns ETrue if the datapath could be constructed else false
|
sl@0
|
398 |
//sets iCodec to the appropriate codec.& sets its own iSink/iSource FourCC datatype codes
|
sl@0
|
399 |
iDataPathCreated = EFalse;
|
sl@0
|
400 |
if (aSource && aSink) //have a source and sink
|
sl@0
|
401 |
{ //we have a data source & sink but no codec so try and find one - if required
|
sl@0
|
402 |
TFourCC sourceFourCCCode = aSource->SourceDataTypeCode(iMediaId); //get MDataSource data type fourCC code
|
sl@0
|
403 |
TFourCC sinkFourCCCode = aSink->SinkDataTypeCode(iMediaId); //get MDataSink data type fourCC code
|
sl@0
|
404 |
if ((sourceFourCCCode != sinkFourCCCode) && //MDataSource & MDataSink datatypes are not compatible
|
sl@0
|
405 |
(sourceFourCCCode != KMMFFourCCCodeNULL) && (sinkFourCCCode != KMMFFourCCCodeNULL))
|
sl@0
|
406 |
{//we need a codec to make the conversion between the source and the sink
|
sl@0
|
407 |
CMMFCodec* codec = CMMFCodec::NewL(sourceFourCCCode, sinkFourCCCode);
|
sl@0
|
408 |
|
sl@0
|
409 |
if (codec)
|
sl@0
|
410 |
{
|
sl@0
|
411 |
delete iCodec;
|
sl@0
|
412 |
iCodec = codec;
|
sl@0
|
413 |
//data path created ie have source/sink and can match their datatypes
|
sl@0
|
414 |
iDataPathCreated = ETrue;
|
sl@0
|
415 |
|
sl@0
|
416 |
//now we have an source attached we need to configure the codec for sample rate
|
sl@0
|
417 |
//and number of channels
|
sl@0
|
418 |
|
sl@0
|
419 |
//prepare a package to send to a codec
|
sl@0
|
420 |
TMMFAudioConfig audioSettings;
|
sl@0
|
421 |
|
sl@0
|
422 |
//test for decoder
|
sl@0
|
423 |
if (aSource->DataSourceType() == KUidMmfFormatDecode)
|
sl@0
|
424 |
{
|
sl@0
|
425 |
audioSettings.iSampleRate = static_cast<CMMFFormatDecode*>(aSource)->SampleRate();
|
sl@0
|
426 |
audioSettings.iChannels = static_cast<CMMFFormatDecode*>(aSource)->NumChannels();
|
sl@0
|
427 |
}
|
sl@0
|
428 |
|
sl@0
|
429 |
//package up to send to codec
|
sl@0
|
430 |
TPckgBuf<TMMFAudioConfig> configPackage(audioSettings);
|
sl@0
|
431 |
|
sl@0
|
432 |
//we need to catch User::Leave(KErrNotSupported) as by default most codecs
|
sl@0
|
433 |
//do not support the ConfigureL method.
|
sl@0
|
434 |
TRAPD(err,iCodec->ConfigureL(KUidCodecAudioConfig, configPackage));
|
sl@0
|
435 |
// need to check other error here
|
sl@0
|
436 |
if (err != KErrNone && err != KErrNotSupported)
|
sl@0
|
437 |
{
|
sl@0
|
438 |
User::Leave(err);
|
sl@0
|
439 |
}
|
sl@0
|
440 |
}
|
sl@0
|
441 |
else
|
sl@0
|
442 |
{
|
sl@0
|
443 |
User::Leave( KErrNotSupported ) ; //couldn't find suitable codec
|
sl@0
|
444 |
}
|
sl@0
|
445 |
} //if (sourceFourCCCode != sinkFourCCCode)
|
sl@0
|
446 |
else
|
sl@0
|
447 |
{ //source & sink fourCC datatypes are the same so no codec is required
|
sl@0
|
448 |
__ASSERT_DEBUG(iCodec == NULL, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
|
sl@0
|
449 |
|
sl@0
|
450 |
iDataPathCreated = ETrue;
|
sl@0
|
451 |
}
|
sl@0
|
452 |
//can assign FourCC codes for the CMMFDataPath
|
sl@0
|
453 |
iSinkFourCC = sourceFourCCCode; //sink because CMMFDataPath is an MDataSink to its MDataSource!
|
sl@0
|
454 |
iSourceFourCC = sinkFourCCCode; //source because CMMFDataPath is an MDataSource to its MDataSink!
|
sl@0
|
455 |
//If sink & source need its own Prime() done in controller
|
sl@0
|
456 |
}
|
sl@0
|
457 |
}
|
sl@0
|
458 |
|
sl@0
|
459 |
/**
|
sl@0
|
460 |
Clears the specified buffer.
|
sl@0
|
461 |
|
sl@0
|
462 |
Pure virtual dummy implementation, not needed by datapath
|
sl@0
|
463 |
comes from MDataSink - CMMFData path is a sink to its MDataSource.
|
sl@0
|
464 |
|
sl@0
|
465 |
This is only required for an active push MDataSource requesting a buffer empty.
|
sl@0
|
466 |
|
sl@0
|
467 |
@param aBuffer
|
sl@0
|
468 |
The buffer to empty.
|
sl@0
|
469 |
@param aSupplier
|
sl@0
|
470 |
The MDataSource supplying this buffer.
|
sl@0
|
471 |
@param aMediaId
|
sl@0
|
472 |
An optional mediaID parameter when there are multiple buffers arriving of different media types.
|
sl@0
|
473 |
|
sl@0
|
474 |
*/
|
sl@0
|
475 |
EXPORT_C void CMMFDataPath::EmptyBufferL(CMMFBuffer* /* aBuffer */, MDataSource* /*aSupplier*/, TMediaId /*aMediaId*/)
|
sl@0
|
476 |
{
|
sl@0
|
477 |
//not implemented
|
sl@0
|
478 |
}
|
sl@0
|
479 |
|
sl@0
|
480 |
|
sl@0
|
481 |
|
sl@0
|
482 |
/*
|
sl@0
|
483 |
* FillSourceBufferL
|
sl@0
|
484 |
*
|
sl@0
|
485 |
* Function to get data from the datapath's iDataSource
|
sl@0
|
486 |
*/
|
sl@0
|
487 |
|
sl@0
|
488 |
void CMMFDataPath::FillSourceBufferL()
|
sl@0
|
489 |
{
|
sl@0
|
490 |
#ifdef _DP_DEBUG
|
sl@0
|
491 |
RDebug::Print(_L("DP::FillSourceBufferL tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
492 |
#endif
|
sl@0
|
493 |
|
sl@0
|
494 |
__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
495 |
|
sl@0
|
496 |
|
sl@0
|
497 |
// clear the no-more-source flag here (as well as in PlayL()) because
|
sl@0
|
498 |
// there may have been a re-position since the last call to BufferFilledL()
|
sl@0
|
499 |
iNoMoreSourceData = EFalse;
|
sl@0
|
500 |
|
sl@0
|
501 |
if(!iObtainingAsyncSourceBuffer)
|
sl@0
|
502 |
{//this is a normal request for data.
|
sl@0
|
503 |
//If we are getting asynchronous buffers, then can't do this as iSourceBuffer == NULL
|
sl@0
|
504 |
iSourceBuffer->SetFrameNumber(++iCurrentSourceFrameNumber); //so source knows which data to load buffer with
|
sl@0
|
505 |
iSourceBuffer->SetStatus(EBeingFilled);
|
sl@0
|
506 |
iSourceBuffer->SetLastBuffer(EFalse);
|
sl@0
|
507 |
}
|
sl@0
|
508 |
|
sl@0
|
509 |
#ifdef _DP_DEBUG
|
sl@0
|
510 |
RDebug::Print(_L("DP asking for buffer %d - ptr=0x%x (this 0x%x)\n"), iCurrentSourceFrameNumber, iSourceBuffer,this);
|
sl@0
|
511 |
#endif
|
sl@0
|
512 |
|
sl@0
|
513 |
iSourceBufferWithSource = ETrue;
|
sl@0
|
514 |
|
sl@0
|
515 |
// wait for BufferFilled callback from source. Do this here as some sources cause
|
sl@0
|
516 |
//re-entrancy into data path via BufferFilledL
|
sl@0
|
517 |
ChangeDataPathTransferState(EWaitSource);
|
sl@0
|
518 |
|
sl@0
|
519 |
iDataSource->FillBufferL(iSourceBuffer, this, iMediaId);
|
sl@0
|
520 |
|
sl@0
|
521 |
#ifdef _DP_DEBUG
|
sl@0
|
522 |
RDebug::Print(_L("DP::FillSourceBufferL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
523 |
#endif
|
sl@0
|
524 |
}
|
sl@0
|
525 |
|
sl@0
|
526 |
|
sl@0
|
527 |
/**
|
sl@0
|
528 |
Indicates the data source has filled the specified buffer.
|
sl@0
|
529 |
|
sl@0
|
530 |
Called by the CMMFDataPath's MDataSource when it has filled the buffer.
|
sl@0
|
531 |
|
sl@0
|
532 |
@param aBuffer
|
sl@0
|
533 |
A pointer to the filled buffer.
|
sl@0
|
534 |
*/
|
sl@0
|
535 |
EXPORT_C void CMMFDataPath::BufferFilledL(CMMFBuffer* aBuffer)
|
sl@0
|
536 |
{
|
sl@0
|
537 |
#ifdef _DP_DEBUG
|
sl@0
|
538 |
RDebug::Print(_L("DP::BufferFilledL src has filled buffer %d (ptr=0x%x) with %d bytes EoF = %d tick-%d (this 0x%x)\n"),aBuffer->FrameNumber(),aBuffer, aBuffer->BufferSize(),aBuffer->LastBuffer(), User::TickCount(),this);
|
sl@0
|
539 |
#endif
|
sl@0
|
540 |
|
sl@0
|
541 |
//This assertion is commented because of PDEF117405
|
sl@0
|
542 |
//state only used if we are passing data
|
sl@0
|
543 |
//__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
544 |
|
sl@0
|
545 |
__ASSERT_DEBUG((!iNoMoreSourceData), Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
546 |
|
sl@0
|
547 |
iSourceBufferWithSource = EFalse;
|
sl@0
|
548 |
|
sl@0
|
549 |
//Has the datapath stopped running, if so were not interested in any callbacks.
|
sl@0
|
550 |
if(iState == EStopped || iState == EPrimed || (iPauseCalled && iState != ERecording))
|
sl@0
|
551 |
{
|
sl@0
|
552 |
#ifdef _DP_DEBUG
|
sl@0
|
553 |
RDebug::Print(_L("DP::BufferFilledL called while not expecting callback iState=%d iPauseCalled=%d (this 0x%x)\n"),iState, iPauseCalled,this);
|
sl@0
|
554 |
#endif
|
sl@0
|
555 |
return;
|
sl@0
|
556 |
}
|
sl@0
|
557 |
|
sl@0
|
558 |
#ifdef REPOSITION_SPEEDUP
|
sl@0
|
559 |
// if the source has been re-positioned, then go & get some more source data now
|
sl@0
|
560 |
if (!iObtainingAsyncSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
|
sl@0
|
561 |
{
|
sl@0
|
562 |
#ifdef _DP_DEBUG
|
sl@0
|
563 |
RDebug::Print(_L("DP::BufferFilledL source was re-positioned re-requesting source data (this 0x%x)\n"),this);
|
sl@0
|
564 |
#endif
|
sl@0
|
565 |
ChangeDataPathTransferState(ENeedSourceData);
|
sl@0
|
566 |
return;
|
sl@0
|
567 |
}
|
sl@0
|
568 |
#endif //REPOSITION_SPEEDUP
|
sl@0
|
569 |
|
sl@0
|
570 |
//bufer is NULL, indicating no more source data.
|
sl@0
|
571 |
if (!aBuffer)
|
sl@0
|
572 |
{
|
sl@0
|
573 |
//If we only hold a reference to the source buffer, set that to NULL
|
sl@0
|
574 |
if(iSnkBufRef)
|
sl@0
|
575 |
iSourceBuffer = NULL;
|
sl@0
|
576 |
|
sl@0
|
577 |
|
sl@0
|
578 |
iNoMoreSourceData = ETrue;
|
sl@0
|
579 |
|
sl@0
|
580 |
if(!iCodec || //there's only one buffer and that has been returned as NULL, so must be end of data
|
sl@0
|
581 |
iSinkBufferWithSink) //buffer is with sink, we don't have any more data to put in it, so must be end of data
|
sl@0
|
582 |
{
|
sl@0
|
583 |
ChangeDataPathTransferState(EEndOfData);
|
sl@0
|
584 |
}
|
sl@0
|
585 |
else //sink buffer is with datapath, see if there is anything to send to sink
|
sl@0
|
586 |
ChangeDataPathTransferState(ENeedToMatchSourceToSink);
|
sl@0
|
587 |
|
sl@0
|
588 |
#ifdef _DP_DEBUG
|
sl@0
|
589 |
RDebug::Print(_L("DP::BufferFilledL DONE aBuffer==NULL tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
590 |
#endif
|
sl@0
|
591 |
return;
|
sl@0
|
592 |
}
|
sl@0
|
593 |
|
sl@0
|
594 |
|
sl@0
|
595 |
//We were waiting for a response from the source to get an asynchronous buffer.
|
sl@0
|
596 |
//We now have it, and we proceed to transfer this data to the sink.
|
sl@0
|
597 |
if (iObtainingAsyncSourceBuffer)
|
sl@0
|
598 |
{
|
sl@0
|
599 |
iObtainingAsyncSourceBuffer = EFalse;
|
sl@0
|
600 |
}
|
sl@0
|
601 |
|
sl@0
|
602 |
|
sl@0
|
603 |
aBuffer->SetStatus(EFull);
|
sl@0
|
604 |
|
sl@0
|
605 |
if(iSourceBuffer != aBuffer)
|
sl@0
|
606 |
{//buffer has been changed by the source
|
sl@0
|
607 |
iSourceBuffer = aBuffer;
|
sl@0
|
608 |
if (!(iBuffersToUse & ENeedSinkBuffer))
|
sl@0
|
609 |
{//we only need one buffer and use source
|
sl@0
|
610 |
iSinkBuffer = iSourceBuffer;
|
sl@0
|
611 |
iSnkBufRef = ETrue;
|
sl@0
|
612 |
}
|
sl@0
|
613 |
#ifdef _DP_DEBUG
|
sl@0
|
614 |
RDebug::Print(_L("DP::BufferFilledL - iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
615 |
#endif
|
sl@0
|
616 |
}
|
sl@0
|
617 |
//Is this the last buffer from the source (0 length or LastBuffer flag set)
|
sl@0
|
618 |
//or have reached the end of the play window; we only look at the play window here
|
sl@0
|
619 |
//if we are converting. For conversion we look at the data we have read. This is then passed onto
|
sl@0
|
620 |
//the source
|
sl@0
|
621 |
if (!iSourceBuffer->BufferSize() || iSourceBuffer->LastBuffer() ||
|
sl@0
|
622 |
(((iState == EConverting) || (iState == EPlaying)) && (iPlayWindowEndPosition < iCachedSourceDuration) && ( InputPosition() >= iPlayWindowEndPosition )))
|
sl@0
|
623 |
{
|
sl@0
|
624 |
#ifdef _DP_DEBUG
|
sl@0
|
625 |
RDebug::Print(_L("DP::BufferFilledL end of input data tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
626 |
RDebug::Print(_L("iSourceBuffer->BufferSize()=%d\n"),iSourceBuffer->BufferSize());
|
sl@0
|
627 |
RDebug::Print(_L("iSourceBuffer->LastBuffer()=%d\n"),iSourceBuffer->LastBuffer());
|
sl@0
|
628 |
RDebug::Print(_L("InputPosition()=%d >= iPlayWindowEndPosition=%d\n"),I64INT(InputPosition().Int64()),I64INT(iPlayWindowEndPosition.Int64()));
|
sl@0
|
629 |
#endif
|
sl@0
|
630 |
iNoMoreSourceData = ETrue;
|
sl@0
|
631 |
iSourceBuffer->SetLastBuffer(ETrue); //just in-case we are terminating on BufferSize == 0 or play window
|
sl@0
|
632 |
}
|
sl@0
|
633 |
|
sl@0
|
634 |
|
sl@0
|
635 |
if (!iCodec)
|
sl@0
|
636 |
ChangeDataPathTransferState(ESendDataToSink);
|
sl@0
|
637 |
else if(!iSinkBufferWithSink) //sink buffer is with data path, can try to fill it
|
sl@0
|
638 |
ChangeDataPathTransferState(ENeedToMatchSourceToSink);
|
sl@0
|
639 |
//else wait for sink to return buffer BufferEmptied will send us into ENeedToMatchSourceToSink state
|
sl@0
|
640 |
|
sl@0
|
641 |
#ifdef _DP_DEBUG
|
sl@0
|
642 |
RDebug::Print(_L("DP::BufferFilledL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
643 |
#endif
|
sl@0
|
644 |
}
|
sl@0
|
645 |
|
sl@0
|
646 |
|
sl@0
|
647 |
|
sl@0
|
648 |
|
sl@0
|
649 |
/*
|
sl@0
|
650 |
* FillSinkBufferL
|
sl@0
|
651 |
*
|
sl@0
|
652 |
* Function to take the data from an already full source buffer and by using
|
sl@0
|
653 |
* a codec if necessary fills the sink buffer
|
sl@0
|
654 |
*/
|
sl@0
|
655 |
|
sl@0
|
656 |
void CMMFDataPath::FillSinkBufferL()
|
sl@0
|
657 |
{
|
sl@0
|
658 |
#ifdef _DP_DEBUG
|
sl@0
|
659 |
RDebug::Print(_L("DP::FillSinkBufferL tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
660 |
#endif
|
sl@0
|
661 |
|
sl@0
|
662 |
//This state is only used if we are passing data
|
sl@0
|
663 |
__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
664 |
|
sl@0
|
665 |
//This state is only used if we have a real codec
|
sl@0
|
666 |
__ASSERT_DEBUG(iCodec, Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
667 |
|
sl@0
|
668 |
|
sl@0
|
669 |
//The sink buffer is with the sink so we can't fill it.
|
sl@0
|
670 |
//When it has been emptied, this state will be re-entered from BufferEmptiedL
|
sl@0
|
671 |
if(iSinkBufferWithSink)
|
sl@0
|
672 |
{
|
sl@0
|
673 |
#ifdef _DP_DEBUG
|
sl@0
|
674 |
RDebug::Print(_L("DP::FillSinkBufferL buffer is in use by SINK - DONE (this 0x%x)\n"),this);
|
sl@0
|
675 |
#endif
|
sl@0
|
676 |
ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
|
sl@0
|
677 |
return;
|
sl@0
|
678 |
}
|
sl@0
|
679 |
|
sl@0
|
680 |
//The source buffer is with the source so we can't take data from it.
|
sl@0
|
681 |
//When it has been filled, this state will be re-entered from BufferFilledL
|
sl@0
|
682 |
if(iSourceBufferWithSource)
|
sl@0
|
683 |
{
|
sl@0
|
684 |
#ifdef _DP_DEBUG
|
sl@0
|
685 |
RDebug::Print(_L("DP::FillSinkBufferL buffer is in use by SOURCE - DONE (this 0x%x)\n"),this);
|
sl@0
|
686 |
#endif
|
sl@0
|
687 |
ChangeDataPathTransferState(EWaitSource); // wait for BufferFilled callback from source
|
sl@0
|
688 |
return;
|
sl@0
|
689 |
}
|
sl@0
|
690 |
|
sl@0
|
691 |
//source buffer is NULL, can't be any more data to send.
|
sl@0
|
692 |
//iNoMoreSourceData is set and the source buffer is empty, can't be any more data to send.
|
sl@0
|
693 |
if(!iSourceBuffer || (iNoMoreSourceData && !iSourceBuffer->BufferSize()))
|
sl@0
|
694 |
{
|
sl@0
|
695 |
if(iSinkBuffer->Status() == EBeingFilled)
|
sl@0
|
696 |
{//if we have data in sink buffer, mark it as last buffer and send
|
sl@0
|
697 |
iSinkBuffer->SetLastBuffer(ETrue);
|
sl@0
|
698 |
ChangeDataPathTransferState(ESendDataToSink);
|
sl@0
|
699 |
}
|
sl@0
|
700 |
else //the sink buffer can't have anything in it
|
sl@0
|
701 |
ChangeDataPathTransferState(EEndOfData);
|
sl@0
|
702 |
}
|
sl@0
|
703 |
|
sl@0
|
704 |
#ifdef REPOSITION_SPEEDUP
|
sl@0
|
705 |
// if the source has been re-positioned,
|
sl@0
|
706 |
// speed things up by getting some more source data now
|
sl@0
|
707 |
if(iSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
|
sl@0
|
708 |
{
|
sl@0
|
709 |
#ifdef _DP_DEBUG
|
sl@0
|
710 |
RDebug::Print(_L("DP::FillSinkBufferL() source was re-positioned re-requesting source data (this 0x%x)\n"),this);
|
sl@0
|
711 |
#endif
|
sl@0
|
712 |
ChangeDataPathTransferState(ENeedSourceData);
|
sl@0
|
713 |
return;
|
sl@0
|
714 |
}
|
sl@0
|
715 |
#endif //REPOSITION_SPEEDUP
|
sl@0
|
716 |
|
sl@0
|
717 |
iSinkBuffer->SetStatus(EBeingFilled);
|
sl@0
|
718 |
iSinkBuffer->SetLastBuffer(EFalse);
|
sl@0
|
719 |
|
sl@0
|
720 |
//pass buffer to codec for processing
|
sl@0
|
721 |
iCodecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSinkBuffer);
|
sl@0
|
722 |
//the codec tries to fill the sink buffer to its max length
|
sl@0
|
723 |
//TCodecProcessResult returns the status of the codec Process -
|
sl@0
|
724 |
//this can result in result conditions such as:
|
sl@0
|
725 |
//EProcessComplete - the codec processed all the source data into the sink buffer
|
sl@0
|
726 |
//EProcessIncomplete - the codec filled sink buffer before all the source buffer was processed
|
sl@0
|
727 |
//EDstNotFilled - the codec processed the source buffer but the sink buffer was not filled
|
sl@0
|
728 |
//EEndOfData - the codec detected the end data - all source data in processed but sink may not be full
|
sl@0
|
729 |
//EProcessError - the codec process error condition
|
sl@0
|
730 |
|
sl@0
|
731 |
|
sl@0
|
732 |
switch (iCodecProcessResult.iStatus)
|
sl@0
|
733 |
{
|
sl@0
|
734 |
case TCodecProcessResult::EProcessComplete:
|
sl@0
|
735 |
//finished procesing source data - all data in sink buffer
|
sl@0
|
736 |
{
|
sl@0
|
737 |
#ifdef _DP_DEBUG
|
sl@0
|
738 |
RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EProcessComplete (this 0x%x)\n"),this);
|
sl@0
|
739 |
#endif
|
sl@0
|
740 |
iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
|
sl@0
|
741 |
iSinkBuffer->SetStatus(EFull); //sink buffer is full
|
sl@0
|
742 |
if (iNoMoreSourceData)
|
sl@0
|
743 |
iSinkBuffer->SetLastBuffer(ETrue);
|
sl@0
|
744 |
ChangeDataPathTransferState(ESendDataToSink);// the full sink buffer needs to be sent to the sink
|
sl@0
|
745 |
}
|
sl@0
|
746 |
break;
|
sl@0
|
747 |
case TCodecProcessResult::EProcessIncomplete:
|
sl@0
|
748 |
// the sink was filled before all the src was processed
|
sl@0
|
749 |
// therefore still send everything to sink
|
sl@0
|
750 |
//but datapath needs to carry on processing the source buffer before it gets more source data
|
sl@0
|
751 |
//when sink has emptied data path needs to send rest of data
|
sl@0
|
752 |
{
|
sl@0
|
753 |
#ifdef _DP_DEBUG
|
sl@0
|
754 |
RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EProcessIncomplete (this 0x%x)\n"),this);
|
sl@0
|
755 |
#endif
|
sl@0
|
756 |
TUint sourceBufferPosition = iCodecProcessResult.iSrcBytesProcessed + iSourceBuffer->Position();
|
sl@0
|
757 |
iSourceBuffer->SetPosition(sourceBufferPosition);//update source buffer position
|
sl@0
|
758 |
iSinkBuffer->SetStatus(EFull); //sink & source buffers are both full
|
sl@0
|
759 |
ChangeDataPathTransferState(ESendDataToSink); // the full sink buffer needs to be sent to the sink
|
sl@0
|
760 |
}
|
sl@0
|
761 |
break;
|
sl@0
|
762 |
case TCodecProcessResult::EDstNotFilled:
|
sl@0
|
763 |
// the destination is not full
|
sl@0
|
764 |
{
|
sl@0
|
765 |
#ifdef _DP_DEBUG
|
sl@0
|
766 |
RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EDstNotFilled (this 0x%x)\n"),this);
|
sl@0
|
767 |
#endif
|
sl@0
|
768 |
iSourceBuffer->SetStatus(EAvailable); //source buffer is now available
|
sl@0
|
769 |
TUint sinkBufferPosition = iCodecProcessResult.iDstBytesAdded + iSinkBuffer->Position();
|
sl@0
|
770 |
iSinkBuffer->SetPosition(sinkBufferPosition);//update sink buffer position (still EBeingFilled)
|
sl@0
|
771 |
// if this was the last source buffer, send what we've got (if anything)
|
sl@0
|
772 |
// to the sink... EmptySinkBuffer() should then enter EEndOfData state
|
sl@0
|
773 |
if (iNoMoreSourceData)
|
sl@0
|
774 |
{
|
sl@0
|
775 |
iSinkBuffer->SetLastBuffer(ETrue);
|
sl@0
|
776 |
ChangeDataPathTransferState(ESendDataToSink);//send what we've got to the sink -
|
sl@0
|
777 |
}
|
sl@0
|
778 |
else
|
sl@0
|
779 |
{
|
sl@0
|
780 |
ChangeDataPathTransferState(ENeedSourceData); //need to get more source data to fill sink buffer
|
sl@0
|
781 |
}
|
sl@0
|
782 |
}
|
sl@0
|
783 |
break;
|
sl@0
|
784 |
case TCodecProcessResult::EEndOfData:
|
sl@0
|
785 |
//no more data - send what we've got to the sink
|
sl@0
|
786 |
//note we can't always rely on this - in many cases the codec will not know when
|
sl@0
|
787 |
//it has reached the end of data.
|
sl@0
|
788 |
{
|
sl@0
|
789 |
#ifdef _DP_DEBUG
|
sl@0
|
790 |
RDebug::Print(_L("CMMFDataPath::FillSinkBufferL codec EEndOfData (this 0x%x)\n"),this);
|
sl@0
|
791 |
#endif
|
sl@0
|
792 |
iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
|
sl@0
|
793 |
iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
|
sl@0
|
794 |
|
sl@0
|
795 |
//This only occurs where the codec can detect the end of data, but the source can't
|
sl@0
|
796 |
iNoMoreSourceData=ETrue;
|
sl@0
|
797 |
iSinkBuffer->SetLastBuffer(ETrue);
|
sl@0
|
798 |
|
sl@0
|
799 |
ChangeDataPathTransferState(ESendDataToSink);//send what we've got to the sink -
|
sl@0
|
800 |
//doesn't matter if sink buffer is not full
|
sl@0
|
801 |
}
|
sl@0
|
802 |
break;
|
sl@0
|
803 |
case TCodecProcessResult::EProcessError:
|
sl@0
|
804 |
#ifdef _DP_DEBUG
|
sl@0
|
805 |
RDebug::Print(_L("DP::FillSinkBufferL tick-%d DONE %d (this 0x%x)\n"),User::TickCount(), __LINE__,this);
|
sl@0
|
806 |
#endif
|
sl@0
|
807 |
User::Leave(KErrCorrupt); //codec process error
|
sl@0
|
808 |
break;
|
sl@0
|
809 |
default:
|
sl@0
|
810 |
#ifdef _DP_DEBUG
|
sl@0
|
811 |
RDebug::Print(_L("DP::FillSinkBufferL tick-%d DONE %d (this 0x%x)\n"),User::TickCount(), __LINE__,this);
|
sl@0
|
812 |
#endif
|
sl@0
|
813 |
User::Leave(KErrCorrupt); //should never get here
|
sl@0
|
814 |
}
|
sl@0
|
815 |
#ifdef _DP_DEBUG
|
sl@0
|
816 |
RDebug::Print(_L("DP::FillSinkBufferL - done tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
817 |
#endif
|
sl@0
|
818 |
}
|
sl@0
|
819 |
|
sl@0
|
820 |
|
sl@0
|
821 |
|
sl@0
|
822 |
/**
|
sl@0
|
823 |
Tests whether the data path can create a sink buffer.
|
sl@0
|
824 |
|
sl@0
|
825 |
The default implementation returns false.
|
sl@0
|
826 |
|
sl@0
|
827 |
@return ETrue if the data path can create a sink buffer. EFalse if the data path cannot create a sink buffer.
|
sl@0
|
828 |
*/
|
sl@0
|
829 |
EXPORT_C TBool CMMFDataPath::CanCreateSinkBuffer()
|
sl@0
|
830 |
{
|
sl@0
|
831 |
return NULL; //CMMFDataPath cannot create buffer
|
sl@0
|
832 |
}
|
sl@0
|
833 |
|
sl@0
|
834 |
/**
|
sl@0
|
835 |
Creates a sink buffer according to the specifed media ID.
|
sl@0
|
836 |
|
sl@0
|
837 |
Intended for synchronous usage (buffers supplied by datapath for an MDataSink).
|
sl@0
|
838 |
This method is essentially a dummy implementation of an MDataSink pure virtual.
|
sl@0
|
839 |
|
sl@0
|
840 |
The default implementation returns NULL.
|
sl@0
|
841 |
|
sl@0
|
842 |
@param aMediaId
|
sl@0
|
843 |
An optional mediaID parameter when there are multiple buffers arriving of different media types.
|
sl@0
|
844 |
|
sl@0
|
845 |
@return Returns NULL in this instance as datapath can't create sink buffers
|
sl@0
|
846 |
*/
|
sl@0
|
847 |
EXPORT_C CMMFBuffer* CMMFDataPath::CreateSinkBufferL(TMediaId /*aMediaId*/)
|
sl@0
|
848 |
{//CMMFDataPath can't create buffers
|
sl@0
|
849 |
return NULL;
|
sl@0
|
850 |
}
|
sl@0
|
851 |
|
sl@0
|
852 |
/**
|
sl@0
|
853 |
Creates a sink buffer according to the specifed media ID and reference.
|
sl@0
|
854 |
|
sl@0
|
855 |
Intended for asynchronous usage (buffers supplied by Devsound device).
|
sl@0
|
856 |
This method is essentially a dummy implementation of an MDataSink pure virtual.
|
sl@0
|
857 |
|
sl@0
|
858 |
The default implementation returns NULL.
|
sl@0
|
859 |
|
sl@0
|
860 |
@param aMediaId
|
sl@0
|
861 |
An optional mediaID parameter when there are multiple buffers arriving for different media types.
|
sl@0
|
862 |
@param aReference
|
sl@0
|
863 |
A boolean indicating buffer ownership.
|
sl@0
|
864 |
|
sl@0
|
865 |
@return Returns NULL in this instance as datapath can't create sink buffers.
|
sl@0
|
866 |
*/
|
sl@0
|
867 |
EXPORT_C CMMFBuffer* CMMFDataPath::CreateSinkBufferL(TMediaId /*aMediaId*/, TBool& /*aReference*/)
|
sl@0
|
868 |
{//CMMFDataPath can't create buffers
|
sl@0
|
869 |
return NULL;
|
sl@0
|
870 |
}
|
sl@0
|
871 |
|
sl@0
|
872 |
/**
|
sl@0
|
873 |
Gets the sink's data type for the specified media ID.
|
sl@0
|
874 |
|
sl@0
|
875 |
@param aMediaId
|
sl@0
|
876 |
An optional parameter to specifiy the specific stream when datasource contains more than one stream of data
|
sl@0
|
877 |
@return The sink's data type.
|
sl@0
|
878 |
*/
|
sl@0
|
879 |
EXPORT_C TFourCC CMMFDataPath::SinkDataTypeCode(TMediaId /*aMediaId*/)
|
sl@0
|
880 |
{
|
sl@0
|
881 |
return(iSinkFourCC);
|
sl@0
|
882 |
}
|
sl@0
|
883 |
|
sl@0
|
884 |
/**
|
sl@0
|
885 |
Fills the specified buffer.
|
sl@0
|
886 |
|
sl@0
|
887 |
Pure virtual dummy implementation, not needed by datapath
|
sl@0
|
888 |
comes from MDataSink - CMMFData path is a source to its MDataSink
|
sl@0
|
889 |
|
sl@0
|
890 |
Only required for an active pull MDataSink requesting a buffer fill. The default implementation is empty.
|
sl@0
|
891 |
|
sl@0
|
892 |
@param aBuffer
|
sl@0
|
893 |
The buffer to fill.
|
sl@0
|
894 |
@param aConsumer
|
sl@0
|
895 |
The MDataSink supplying this buffer.
|
sl@0
|
896 |
@param aMediaId
|
sl@0
|
897 |
An optional mediaID parameter when there are multiple buffers arriving of different media types
|
sl@0
|
898 |
*/
|
sl@0
|
899 |
EXPORT_C void CMMFDataPath::FillBufferL(CMMFBuffer* /*aBuffer*/, MDataSink* /*aConsumer*/, TMediaId /*aMediaId*/)
|
sl@0
|
900 |
{
|
sl@0
|
901 |
//not implementated
|
sl@0
|
902 |
}
|
sl@0
|
903 |
|
sl@0
|
904 |
void CMMFDataPath::SetBuffersAvailable()
|
sl@0
|
905 |
{
|
sl@0
|
906 |
// set source buffer to be available
|
sl@0
|
907 |
if (iSourceBuffer)
|
sl@0
|
908 |
iSourceBuffer->SetStatus(EAvailable);
|
sl@0
|
909 |
// set sink buffer to be available
|
sl@0
|
910 |
if (iSinkBuffer)
|
sl@0
|
911 |
iSinkBuffer->SetStatus(EAvailable);
|
sl@0
|
912 |
}
|
sl@0
|
913 |
|
sl@0
|
914 |
void CMMFDataPath::ResetRefBuffers()
|
sl@0
|
915 |
{
|
sl@0
|
916 |
#ifdef _DP_DEBUG
|
sl@0
|
917 |
RDebug::Print(_L("DP::ResetRefBuffers iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
918 |
#endif
|
sl@0
|
919 |
|
sl@0
|
920 |
// Reset the buffer pointers to NULL if they are supplied by DevSound
|
sl@0
|
921 |
// We do this because buffers that are not owned by the datapath may not be valid any more.
|
sl@0
|
922 |
if (iSrcBufRef)
|
sl@0
|
923 |
{
|
sl@0
|
924 |
iSourceBuffer = NULL;
|
sl@0
|
925 |
}
|
sl@0
|
926 |
if (iSnkBufRef)
|
sl@0
|
927 |
{
|
sl@0
|
928 |
iSinkBuffer = NULL;
|
sl@0
|
929 |
}
|
sl@0
|
930 |
}
|
sl@0
|
931 |
|
sl@0
|
932 |
|
sl@0
|
933 |
|
sl@0
|
934 |
|
sl@0
|
935 |
TInt CMMFDataPath::DetermineBuffersToUseL(void) const
|
sl@0
|
936 |
{
|
sl@0
|
937 |
TInt buffs = ENoBuffers;
|
sl@0
|
938 |
if(iCodec)
|
sl@0
|
939 |
{//Using a real Codec, need both sets of buffers
|
sl@0
|
940 |
if(!iDataSink->CanCreateSinkBuffer() || ! iDataSource->CanCreateSourceBuffer())
|
sl@0
|
941 |
User::Leave(KErrNotSupported);
|
sl@0
|
942 |
|
sl@0
|
943 |
buffs = CMMFDataPath::ENeedSinkBuffer | CMMFDataPath::ENeedSourceBuffer;
|
sl@0
|
944 |
}
|
sl@0
|
945 |
else //we are using a Null Codec, only need one buffer, but which one?
|
sl@0
|
946 |
{//use buffer from DevSound, if no DevSound (ie, clip to clip), prefer source buffer.
|
sl@0
|
947 |
//If preferring source but it can't create buffers, use sink.
|
sl@0
|
948 |
if ((iDataSink->DataSinkType() == KUidMmfAudioOutput) && (iDataSink->CanCreateSinkBuffer()))
|
sl@0
|
949 |
buffs = ENeedSinkBuffer;
|
sl@0
|
950 |
else if(iDataSource->CanCreateSourceBuffer())
|
sl@0
|
951 |
buffs = ENeedSourceBuffer;
|
sl@0
|
952 |
else if(iDataSink->CanCreateSinkBuffer())
|
sl@0
|
953 |
buffs = ENeedSinkBuffer;
|
sl@0
|
954 |
else
|
sl@0
|
955 |
User::Leave(KErrNotSupported);
|
sl@0
|
956 |
}
|
sl@0
|
957 |
return buffs;
|
sl@0
|
958 |
}
|
sl@0
|
959 |
|
sl@0
|
960 |
|
sl@0
|
961 |
|
sl@0
|
962 |
/*
|
sl@0
|
963 |
* InitializeSinkL
|
sl@0
|
964 |
*
|
sl@0
|
965 |
* Function to initialize iDataSink before it can start sending data
|
sl@0
|
966 |
* This is a one time prime. This will synchronize DataPath's data driving
|
sl@0
|
967 |
* mechanism with HwDevice implementation.
|
sl@0
|
968 |
*
|
sl@0
|
969 |
* This initialisation method detects its attached sources and sinks and makes adjustments to the state machine
|
sl@0
|
970 |
* This avoid the possibility of NULL buffers (not yet returned by an asychronous sink or source) being passed around the MMF
|
sl@0
|
971 |
*/
|
sl@0
|
972 |
|
sl@0
|
973 |
void CMMFDataPath::InitializeSinkL()
|
sl@0
|
974 |
{
|
sl@0
|
975 |
#ifdef _DP_DEBUG
|
sl@0
|
976 |
RDebug::Print(_L("DP::InitializeSinkL iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
977 |
#endif
|
sl@0
|
978 |
|
sl@0
|
979 |
//state only used if we are passing data
|
sl@0
|
980 |
__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
981 |
|
sl@0
|
982 |
iObtainingAsyncSinkBuffer = EFalse;
|
sl@0
|
983 |
|
sl@0
|
984 |
if (iBuffersToUse & ENeedSinkBuffer)
|
sl@0
|
985 |
{
|
sl@0
|
986 |
//Buffers are initially created in the Prime method. But following a pause, we must re-create
|
sl@0
|
987 |
//any referenced buffers, so try direct creation.
|
sl@0
|
988 |
//NB: this does mean we are trying this twice, Prime and here
|
sl@0
|
989 |
if (!iSinkBuffer) //we may already have a buffer from a previous initialization
|
sl@0
|
990 |
{
|
sl@0
|
991 |
TRAPD(err, iSinkBuffer = iDataSink->CreateSinkBufferL(iMediaId, iSnkBufRef));
|
sl@0
|
992 |
if(err != KErrNone && err != KErrNotSupported)
|
sl@0
|
993 |
User::Leave(err);
|
sl@0
|
994 |
}
|
sl@0
|
995 |
|
sl@0
|
996 |
|
sl@0
|
997 |
//If buffer has not been supplied via CreateSinkBufferL,
|
sl@0
|
998 |
//must use asynchronous buffer creation
|
sl@0
|
999 |
if (!iSinkBuffer)
|
sl@0
|
1000 |
{
|
sl@0
|
1001 |
iObtainingAsyncSinkBuffer = ETrue;
|
sl@0
|
1002 |
ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
|
sl@0
|
1003 |
iDataSink->EmptyBufferL(iSinkBuffer, this, iMediaId);
|
sl@0
|
1004 |
}
|
sl@0
|
1005 |
else
|
sl@0
|
1006 |
{
|
sl@0
|
1007 |
//we have a sink buffer from CreateSinkBufferL
|
sl@0
|
1008 |
iSinkBuffer->SetStatus(EAvailable);
|
sl@0
|
1009 |
|
sl@0
|
1010 |
if (iBuffersToUse & ENeedSourceBuffer)
|
sl@0
|
1011 |
{//need a source buffer, go get it
|
sl@0
|
1012 |
ChangeDataPathTransferState(EInitializeSource);
|
sl@0
|
1013 |
}
|
sl@0
|
1014 |
else
|
sl@0
|
1015 |
{//only need one buffer, use sink
|
sl@0
|
1016 |
iSourceBuffer = iSinkBuffer;
|
sl@0
|
1017 |
iSrcBufRef = ETrue; //the src buffer is not to be deleted
|
sl@0
|
1018 |
|
sl@0
|
1019 |
ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
|
sl@0
|
1020 |
}
|
sl@0
|
1021 |
}
|
sl@0
|
1022 |
}
|
sl@0
|
1023 |
else
|
sl@0
|
1024 |
{//don't need a sink buffer, but we need a source one
|
sl@0
|
1025 |
ChangeDataPathTransferState(EInitializeSource);
|
sl@0
|
1026 |
}
|
sl@0
|
1027 |
|
sl@0
|
1028 |
#ifdef _DP_DEBUG
|
sl@0
|
1029 |
RDebug::Print(_L("DP::InitializeSinkL - DONE iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
1030 |
#endif
|
sl@0
|
1031 |
}
|
sl@0
|
1032 |
|
sl@0
|
1033 |
|
sl@0
|
1034 |
/*
|
sl@0
|
1035 |
* InitializeSourceL
|
sl@0
|
1036 |
*
|
sl@0
|
1037 |
* Function to initialize iDataSource before it can start sending data
|
sl@0
|
1038 |
* This is a one time prime. This will synchronize DataPath's data driving
|
sl@0
|
1039 |
* mechanism with HwDevice implementation.
|
sl@0
|
1040 |
*
|
sl@0
|
1041 |
* This initialisation method detects its attached sources and sinks and makes adjustments to the state machine
|
sl@0
|
1042 |
* This avoid the possibility of NULL buffers (not yet returned by an asychronous sink or source) being passed around the MMF
|
sl@0
|
1043 |
*/
|
sl@0
|
1044 |
|
sl@0
|
1045 |
void CMMFDataPath::InitializeSourceL()
|
sl@0
|
1046 |
{
|
sl@0
|
1047 |
#ifdef _DP_DEBUG
|
sl@0
|
1048 |
RDebug::Print(_L("DP::InitializeSourceL - iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
1049 |
#endif
|
sl@0
|
1050 |
|
sl@0
|
1051 |
//state only used if we are passing data
|
sl@0
|
1052 |
__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording), Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
1053 |
|
sl@0
|
1054 |
iObtainingAsyncSourceBuffer = EFalse;
|
sl@0
|
1055 |
|
sl@0
|
1056 |
if (iBuffersToUse & ENeedSourceBuffer)
|
sl@0
|
1057 |
{
|
sl@0
|
1058 |
//Buffers are initially created in the Prime method. But following a pause, we must re-create
|
sl@0
|
1059 |
//any referenced buffers, so try direct creation.
|
sl@0
|
1060 |
//NB: this does mean we are trying this twice, Prime and here.
|
sl@0
|
1061 |
if (!iSourceBuffer) //we may already have a buffer from a previous initialization
|
sl@0
|
1062 |
{
|
sl@0
|
1063 |
TRAPD(err, iSourceBuffer = iDataSource->CreateSourceBufferL(iMediaId,*iSinkBuffer, iSrcBufRef));
|
sl@0
|
1064 |
if(err != KErrNone && err != KErrNotSupported)
|
sl@0
|
1065 |
User::Leave(err);
|
sl@0
|
1066 |
}
|
sl@0
|
1067 |
|
sl@0
|
1068 |
|
sl@0
|
1069 |
//If buffer has not been supplied via CreateSourceBufferL
|
sl@0
|
1070 |
//must use asynchronous buffer creation
|
sl@0
|
1071 |
if (!iSourceBuffer)
|
sl@0
|
1072 |
{
|
sl@0
|
1073 |
iObtainingAsyncSourceBuffer = ETrue;
|
sl@0
|
1074 |
ChangeDataPathTransferState(ENeedSourceData);
|
sl@0
|
1075 |
}
|
sl@0
|
1076 |
else
|
sl@0
|
1077 |
{//we have a source buffer from CreateSourceBufferL
|
sl@0
|
1078 |
iSourceBuffer->SetStatus(EAvailable);
|
sl@0
|
1079 |
|
sl@0
|
1080 |
if (!(iBuffersToUse & ENeedSinkBuffer))
|
sl@0
|
1081 |
{//only need one buffer, use sink
|
sl@0
|
1082 |
iSinkBuffer = iSourceBuffer;
|
sl@0
|
1083 |
iSnkBufRef = ETrue;
|
sl@0
|
1084 |
}
|
sl@0
|
1085 |
|
sl@0
|
1086 |
ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
|
sl@0
|
1087 |
}
|
sl@0
|
1088 |
}
|
sl@0
|
1089 |
else
|
sl@0
|
1090 |
{//don't need a source buffer, use sinks
|
sl@0
|
1091 |
if(iSinkBuffer)
|
sl@0
|
1092 |
{
|
sl@0
|
1093 |
iSourceBuffer = iSinkBuffer;
|
sl@0
|
1094 |
iSrcBufRef = iSnkBufRef;
|
sl@0
|
1095 |
SetBuffersAvailable();
|
sl@0
|
1096 |
}
|
sl@0
|
1097 |
#ifdef _DP_DEBUG
|
sl@0
|
1098 |
else
|
sl@0
|
1099 |
Panic(EMMFDataPathPanicProgrammingError,__LINE__);
|
sl@0
|
1100 |
#endif
|
sl@0
|
1101 |
ChangeDataPathTransferState(ENeedSourceData); //got all buffers, start getting data
|
sl@0
|
1102 |
|
sl@0
|
1103 |
|
sl@0
|
1104 |
#ifdef _DP_DEBUG
|
sl@0
|
1105 |
RDebug::Print(_L("DP::InitializeSourceL - iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
1106 |
#endif
|
sl@0
|
1107 |
}
|
sl@0
|
1108 |
}
|
sl@0
|
1109 |
|
sl@0
|
1110 |
/*
|
sl@0
|
1111 |
* EmptySinkBufferL
|
sl@0
|
1112 |
*
|
sl@0
|
1113 |
* Function to pass a full databuffer to the iDataSink
|
sl@0
|
1114 |
*/
|
sl@0
|
1115 |
void CMMFDataPath::EmptySinkBufferL()
|
sl@0
|
1116 |
{
|
sl@0
|
1117 |
#ifdef _DP_DEBUG
|
sl@0
|
1118 |
RDebug::Print(_L("DP::EmptySinkBufferL pass data to sink tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1119 |
if(iSinkBuffer)
|
sl@0
|
1120 |
RDebug::Print(_L("iSinkBuffer %d contains %d bytes eof = %d line %d (this 0x%x)\n"),iSinkBuffer->FrameNumber(), iSinkBuffer->BufferSize(),iSinkBuffer->LastBuffer(),__LINE__,this);
|
sl@0
|
1121 |
#endif
|
sl@0
|
1122 |
|
sl@0
|
1123 |
//Before emptying the sink buffer we need to check it has data to empty - this
|
sl@0
|
1124 |
//may not be the case if there is no more data ie iNoMoreSourceData is true.
|
sl@0
|
1125 |
//In this case we need to check to see if there is any data left in the sink
|
sl@0
|
1126 |
//buffer, ie the sink buffer is either full or being filled. If there is not any
|
sl@0
|
1127 |
//data in the sink buffer, ie it is not in the state of EBeingFilled or EFull
|
sl@0
|
1128 |
//then there is nothing to empty so the datapath state is set to EEndOfData and
|
sl@0
|
1129 |
//we return from the procedure.
|
sl@0
|
1130 |
|
sl@0
|
1131 |
//state only used if we are passing data
|
sl@0
|
1132 |
__ASSERT_DEBUG((iState == EPlaying || iState == EConverting || iState == ERecording || (iState == EPrimed && iPauseCalled)), Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
1133 |
__ASSERT_DEBUG(iSinkBuffer &&
|
sl@0
|
1134 |
((iSinkBuffer->Status()==EBeingFilled) || (iSinkBuffer->Status()==EFull)),
|
sl@0
|
1135 |
Panic(EMMFDataPathPanicProgrammingError,__LINE__));
|
sl@0
|
1136 |
|
sl@0
|
1137 |
__ASSERT_DEBUG(iSinkBufferWithSink == EFalse, Panic(EMMFDataPathPanicBadState,__LINE__));
|
sl@0
|
1138 |
|
sl@0
|
1139 |
|
sl@0
|
1140 |
//Due to sinks that may call BuferEmptied directly (ie. re-entrancy onto DataPath) we
|
sl@0
|
1141 |
//must work out next state here. If re-entrancy, the next state may validly get overwritten
|
sl@0
|
1142 |
// in BuferEmptied.
|
sl@0
|
1143 |
if(iObtainingAsyncSinkBuffer) //wait for buffer to be returned in BufferEmptied
|
sl@0
|
1144 |
{
|
sl@0
|
1145 |
ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
|
sl@0
|
1146 |
}
|
sl@0
|
1147 |
|
sl@0
|
1148 |
#ifdef REPOSITION_SPEEDUP
|
sl@0
|
1149 |
// if the source has been re-positioned,
|
sl@0
|
1150 |
// speed things up by getting some more source data now
|
sl@0
|
1151 |
if(iSourceBuffer && iSourceBuffer->FrameNumber() != iCurrentSourceFrameNumber)
|
sl@0
|
1152 |
{
|
sl@0
|
1153 |
#ifdef _DP_DEBUG
|
sl@0
|
1154 |
RDebug::Print(_L("DP::EmptySinkBufferL() source was re-positioned re-requesting source data (this 0x%x)\n"),this);
|
sl@0
|
1155 |
#endif
|
sl@0
|
1156 |
ChangeDataPathTransferState(ENeedSourceData);
|
sl@0
|
1157 |
return;
|
sl@0
|
1158 |
}
|
sl@0
|
1159 |
#endif //REPOSITION_SPEEDUP
|
sl@0
|
1160 |
|
sl@0
|
1161 |
//We have sent data to sink, if we are using a real Codec, we can now get more data from source
|
sl@0
|
1162 |
//if there is any more to get and the codec has emptied it.
|
sl@0
|
1163 |
//NB: No need to check we own the source buffer as we will no be in this state
|
sl@0
|
1164 |
//if we have asked for more source data and haven't received it.
|
sl@0
|
1165 |
else if (iCodec && !iNoMoreSourceData && (iSourceBuffer->Status() == EAvailable))
|
sl@0
|
1166 |
{
|
sl@0
|
1167 |
#ifdef _DP_DEBUG
|
sl@0
|
1168 |
RDebug::Print(_L("ASKING for more source data iCodec = 0x%x iNoMoreSourceData=%d iSourceBufferWithSource = %d (this 0x%x)\n"), iCodec, iNoMoreSourceData, iSourceBufferWithSource,this);
|
sl@0
|
1169 |
#endif
|
sl@0
|
1170 |
ChangeDataPathTransferState(ENeedSourceData);
|
sl@0
|
1171 |
}
|
sl@0
|
1172 |
else
|
sl@0
|
1173 |
{
|
sl@0
|
1174 |
#ifdef _DP_DEBUG
|
sl@0
|
1175 |
RDebug::Print(_L("Not asking for any more source data iCodec = 0x%x iNoMoreSourceData=%d iSourceBufferWithSource = %d iSourceBuffer->Status=%d (this 0x%x)\n"), iCodec, iNoMoreSourceData, iSourceBufferWithSource ,iSourceBuffer->Status(), this);
|
sl@0
|
1176 |
#endif
|
sl@0
|
1177 |
|
sl@0
|
1178 |
//if this is the last buffer, set this flag so we can deal with KErrUnderflow
|
sl@0
|
1179 |
//as a valid termination of playing
|
sl@0
|
1180 |
if(iSinkBuffer->LastBuffer())
|
sl@0
|
1181 |
iAllDataSentToSink=ETrue;
|
sl@0
|
1182 |
|
sl@0
|
1183 |
ChangeDataPathTransferState(EWaitSink); // wait for BufferEmptied callback from sink
|
sl@0
|
1184 |
}
|
sl@0
|
1185 |
|
sl@0
|
1186 |
|
sl@0
|
1187 |
if(!iObtainingAsyncSinkBuffer) //normal data transfer
|
sl@0
|
1188 |
iSinkBuffer->SetFrameNumber(++iCurrentSinkFrameNumber);
|
sl@0
|
1189 |
|
sl@0
|
1190 |
#ifdef _DP_DEBUG
|
sl@0
|
1191 |
RDebug::Print(_L("DP sending buffer %d ptr=0x%x of %d bytes to sink (this 0x%x)\n"), iSinkBuffer->FrameNumber(),iSinkBuffer,iSinkBuffer->BufferSize(),this);
|
sl@0
|
1192 |
#endif
|
sl@0
|
1193 |
|
sl@0
|
1194 |
iSinkBufferWithSink = ETrue;
|
sl@0
|
1195 |
TRAPD(error, iDataSink->EmptyBufferL(iSinkBuffer, this, iMediaId));
|
sl@0
|
1196 |
|
sl@0
|
1197 |
// Check that we haven't exceeded the maximum clip length - if so, go to the EndOfData state
|
sl@0
|
1198 |
// so we perform necessary cleanup.
|
sl@0
|
1199 |
if (error == KErrEof || error == KErrOverflow || error == KErrUnderflow)
|
sl@0
|
1200 |
{
|
sl@0
|
1201 |
#ifdef _DP_DEBUG
|
sl@0
|
1202 |
RDebug::Print(_L("DP::EmptySinkBufferL DONE %d error = %d tick-%d (this 0x%x)\n"),__LINE__, error, User::TickCount(),this);
|
sl@0
|
1203 |
#endif
|
sl@0
|
1204 |
iDataPathCompletedErrorCode = error;
|
sl@0
|
1205 |
ChangeDataPathTransferState(EEndOfData);
|
sl@0
|
1206 |
return;
|
sl@0
|
1207 |
}
|
sl@0
|
1208 |
User::LeaveIfError(error);
|
sl@0
|
1209 |
|
sl@0
|
1210 |
#ifdef _DP_DEBUG
|
sl@0
|
1211 |
RDebug::Print(_L("DP::EmptySinkBufferL - done tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1212 |
#endif
|
sl@0
|
1213 |
}
|
sl@0
|
1214 |
|
sl@0
|
1215 |
|
sl@0
|
1216 |
/**
|
sl@0
|
1217 |
Indicates the data sink has emptied the buffer.
|
sl@0
|
1218 |
|
sl@0
|
1219 |
Called by the CMMFDataPath's MDataSink when it has emptied the buffer
|
sl@0
|
1220 |
|
sl@0
|
1221 |
@param aBuffer
|
sl@0
|
1222 |
The emptied buffer.
|
sl@0
|
1223 |
*/
|
sl@0
|
1224 |
EXPORT_C void CMMFDataPath::BufferEmptiedL(CMMFBuffer* aBuffer)
|
sl@0
|
1225 |
{
|
sl@0
|
1226 |
#ifdef _DP_DEBUG
|
sl@0
|
1227 |
TInt bufNum = 9999;
|
sl@0
|
1228 |
if(aBuffer)
|
sl@0
|
1229 |
bufNum = aBuffer->FrameNumber();
|
sl@0
|
1230 |
else
|
sl@0
|
1231 |
RDebug::Print(_L("DP::BufferEmptiedL returned NULL (this 0x%x)\n"),this);
|
sl@0
|
1232 |
|
sl@0
|
1233 |
RDebug::Print(_L("DP::BufferEmptiedL sink has taken buffer %d (ptr=0x%x) bytes %d eof= %d iNoMoreSourceData = %d tick-%d (this 0x%x)\n"),
|
sl@0
|
1234 |
bufNum, aBuffer, aBuffer->BufferSize(),aBuffer->LastBuffer(), iNoMoreSourceData, User::TickCount(),this);
|
sl@0
|
1235 |
#endif
|
sl@0
|
1236 |
|
sl@0
|
1237 |
iSinkBufferWithSink = EFalse;
|
sl@0
|
1238 |
|
sl@0
|
1239 |
//Has the datapath stopped running, if so were not interested in any callbacks.
|
sl@0
|
1240 |
if(iState == EStopped || (iState == EPrimed && !iPauseCalled))
|
sl@0
|
1241 |
{
|
sl@0
|
1242 |
#ifdef _DP_DEBUG
|
sl@0
|
1243 |
RDebug::Print(_L("DP::BufferEmptiedL called while not expecting callback iState=%d iPauseCalled=%d (this 0x%x)\n"),iState, iPauseCalled,this);
|
sl@0
|
1244 |
#endif
|
sl@0
|
1245 |
return;
|
sl@0
|
1246 |
}
|
sl@0
|
1247 |
|
sl@0
|
1248 |
|
sl@0
|
1249 |
// This will allow MDataSink to send dynamic buffer to DataPath with each BufferEmptiedL request.
|
sl@0
|
1250 |
if (iSinkBuffer != aBuffer) //buffer has been updated
|
sl@0
|
1251 |
{
|
sl@0
|
1252 |
iSinkBuffer = aBuffer;
|
sl@0
|
1253 |
if (!(iBuffersToUse & ENeedSourceBuffer))
|
sl@0
|
1254 |
{ //can use a single buffer
|
sl@0
|
1255 |
iSourceBuffer = iSinkBuffer;
|
sl@0
|
1256 |
iSrcBufRef = iSnkBufRef;
|
sl@0
|
1257 |
}
|
sl@0
|
1258 |
|
sl@0
|
1259 |
}
|
sl@0
|
1260 |
|
sl@0
|
1261 |
iSinkBuffer->SetStatus(EAvailable);
|
sl@0
|
1262 |
|
sl@0
|
1263 |
if (iObtainingAsyncSinkBuffer) //we are creating an asynchronous sink buffer
|
sl@0
|
1264 |
{
|
sl@0
|
1265 |
iObtainingAsyncSinkBuffer = EFalse;
|
sl@0
|
1266 |
|
sl@0
|
1267 |
//we have a sink buffer, should this also be used by the source
|
sl@0
|
1268 |
if (!(iBuffersToUse & ENeedSourceBuffer))
|
sl@0
|
1269 |
{//using a single buffer, so start getting data
|
sl@0
|
1270 |
iSourceBuffer = iSinkBuffer;
|
sl@0
|
1271 |
iSrcBufRef = iSnkBufRef;
|
sl@0
|
1272 |
|
sl@0
|
1273 |
ChangeDataPathTransferState(ENeedSourceData);
|
sl@0
|
1274 |
}
|
sl@0
|
1275 |
else //obtain a separate source buffer
|
sl@0
|
1276 |
ChangeDataPathTransferState(EInitializeSource);
|
sl@0
|
1277 |
|
sl@0
|
1278 |
#ifdef _DP_DEBUG
|
sl@0
|
1279 |
RDebug::Print(_L("DP::BufferEmptiedL - DONE iSourceBuffer=0x%x ref=%d iSinkBuffer=0x%x ref=%d (this 0x%x)\n"),iSourceBuffer,iSrcBufRef,iSinkBuffer,iSnkBufRef, this);
|
sl@0
|
1280 |
#endif
|
sl@0
|
1281 |
return;
|
sl@0
|
1282 |
}
|
sl@0
|
1283 |
|
sl@0
|
1284 |
if(!iCodec) //No Codec in use
|
sl@0
|
1285 |
{
|
sl@0
|
1286 |
if(iNoMoreSourceData)
|
sl@0
|
1287 |
ChangeDataPathTransferState(EEndOfData);//final buffer returned from sink
|
sl@0
|
1288 |
else
|
sl@0
|
1289 |
ChangeDataPathTransferState(ENeedSourceData);//get more data from source
|
sl@0
|
1290 |
}
|
sl@0
|
1291 |
else //real codecs
|
sl@0
|
1292 |
{
|
sl@0
|
1293 |
//There is more source data and src buffer is being filled or we are about to go into
|
sl@0
|
1294 |
// ENeedSourceData state to fill it, so wait for source data to arrive.
|
sl@0
|
1295 |
//NB:if there was more source data and we are using a real codec and source buffer was empty,
|
sl@0
|
1296 |
//more source data would have been requested in EmptySinkBuffer
|
sl@0
|
1297 |
if(!iNoMoreSourceData && (iSourceBufferWithSource || iTransferState == ENeedSourceData))
|
sl@0
|
1298 |
{
|
sl@0
|
1299 |
#ifdef _DP_DEBUG
|
sl@0
|
1300 |
RDebug::Print(_L("DP::BufferEmptiedL - waiting for more source data - DONE tick-%d line %d (this 0x%x)\n"),User::TickCount(),__LINE__,this);
|
sl@0
|
1301 |
#endif
|
sl@0
|
1302 |
return;
|
sl@0
|
1303 |
}
|
sl@0
|
1304 |
|
sl@0
|
1305 |
//source has supplied a NULL buffer or it has been emptied; no more data to send.
|
sl@0
|
1306 |
if(!iSourceBuffer || (iSourceBuffer->Status() == EAvailable))
|
sl@0
|
1307 |
ChangeDataPathTransferState(EEndOfData);
|
sl@0
|
1308 |
else if(iSourceBuffer->Status() == EFull) //there is data in the source buffer, go and get it
|
sl@0
|
1309 |
ChangeDataPathTransferState(ENeedToMatchSourceToSink);
|
sl@0
|
1310 |
|
sl@0
|
1311 |
#ifdef _DP_DEBUG
|
sl@0
|
1312 |
else
|
sl@0
|
1313 |
Panic(EMMFDataPathPanicProgrammingError,__LINE__);
|
sl@0
|
1314 |
#endif
|
sl@0
|
1315 |
}
|
sl@0
|
1316 |
|
sl@0
|
1317 |
|
sl@0
|
1318 |
#ifdef _DP_DEBUG
|
sl@0
|
1319 |
RDebug::Print(_L("DP::BufferEmptiedL - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1320 |
#endif
|
sl@0
|
1321 |
}
|
sl@0
|
1322 |
|
sl@0
|
1323 |
|
sl@0
|
1324 |
|
sl@0
|
1325 |
/**
|
sl@0
|
1326 |
Tests whether the data path can create a source buffer.
|
sl@0
|
1327 |
|
sl@0
|
1328 |
Would expect datapath to always return NULL, so this is a default implementation of a pure virtual from MDataSink.
|
sl@0
|
1329 |
|
sl@0
|
1330 |
The default implementation returns EFalse.
|
sl@0
|
1331 |
|
sl@0
|
1332 |
@return ETrue if the data path can create a source buffer. EFalse if the data path cannot create a source buffer.
|
sl@0
|
1333 |
*/
|
sl@0
|
1334 |
EXPORT_C TBool CMMFDataPath::CanCreateSourceBuffer() //from both MDataSource & MDataSink?
|
sl@0
|
1335 |
{
|
sl@0
|
1336 |
return EFalse; //CMMFDataPath cannot create buffer
|
sl@0
|
1337 |
}
|
sl@0
|
1338 |
|
sl@0
|
1339 |
/**
|
sl@0
|
1340 |
Creates a source buffer.
|
sl@0
|
1341 |
|
sl@0
|
1342 |
Intended for synchronous usage (buffers supplied by datapath for a MDataSource)
|
sl@0
|
1343 |
This method is essentially a dummy implementation of an MDataSource pure virtual.
|
sl@0
|
1344 |
|
sl@0
|
1345 |
The default implementation leaves with KErrNotSupported and returns NULL.
|
sl@0
|
1346 |
|
sl@0
|
1347 |
@param aMediaId
|
sl@0
|
1348 |
An optional mediaID parameter when there are multiple buffers arriving of different media types.
|
sl@0
|
1349 |
@return A pointer to a newly created buffer. Returns NULL in this instance as datapath can't create source buffers
|
sl@0
|
1350 |
*/
|
sl@0
|
1351 |
EXPORT_C CMMFBuffer* CMMFDataPath::CreateSourceBufferL(TMediaId /*aMediaId*/) //CMMFDataPath can't create buffers
|
sl@0
|
1352 |
{
|
sl@0
|
1353 |
User::Leave(KErrNotSupported);
|
sl@0
|
1354 |
return NULL;
|
sl@0
|
1355 |
}
|
sl@0
|
1356 |
|
sl@0
|
1357 |
/**
|
sl@0
|
1358 |
Creates a source buffer according to the specifed media ID and reference.
|
sl@0
|
1359 |
|
sl@0
|
1360 |
Intended for asynchronous usage (buffers supplied by datapath for a MDataSource)
|
sl@0
|
1361 |
This method is essentially a dummy implementation of an MDataSource pure virtual.
|
sl@0
|
1362 |
|
sl@0
|
1363 |
The default implementation leaves with KErrNotSupported and returns NULL.
|
sl@0
|
1364 |
|
sl@0
|
1365 |
@param aMediaId
|
sl@0
|
1366 |
An optional mediaID parameter when there are multiple buffers arriving of different media types.
|
sl@0
|
1367 |
@param aReference
|
sl@0
|
1368 |
A boolean indicating buffer ownership. ETrue if the MDataSource owns the buffer, EFalse if the caller owns the buffer.
|
sl@0
|
1369 |
|
sl@0
|
1370 |
@return A pointer to a newly created buffer. Returns NULL in this instance as datapath can't create source buffers.
|
sl@0
|
1371 |
*/
|
sl@0
|
1372 |
EXPORT_C CMMFBuffer* CMMFDataPath::CreateSourceBufferL(TMediaId /*aMediaId*/, TBool& /*aReference*/) //CMMFDataPath can't create buffers
|
sl@0
|
1373 |
{
|
sl@0
|
1374 |
User::Leave(KErrNotSupported);
|
sl@0
|
1375 |
return NULL;
|
sl@0
|
1376 |
}
|
sl@0
|
1377 |
|
sl@0
|
1378 |
|
sl@0
|
1379 |
/**
|
sl@0
|
1380 |
Gets the source data type for the specified media ID.
|
sl@0
|
1381 |
|
sl@0
|
1382 |
@param aMediaId
|
sl@0
|
1383 |
An optional parameter to specifiy specific stream when datasource contains more than one stream of data.
|
sl@0
|
1384 |
|
sl@0
|
1385 |
@return The source data type.
|
sl@0
|
1386 |
*/
|
sl@0
|
1387 |
EXPORT_C TFourCC CMMFDataPath::SourceDataTypeCode(TMediaId /*aMediaId*/)
|
sl@0
|
1388 |
{
|
sl@0
|
1389 |
return(iSourceFourCC);
|
sl@0
|
1390 |
}
|
sl@0
|
1391 |
|
sl@0
|
1392 |
|
sl@0
|
1393 |
/**
|
sl@0
|
1394 |
Allocates buffers in preparation to play.
|
sl@0
|
1395 |
|
sl@0
|
1396 |
Must be called before calling PlayL().
|
sl@0
|
1397 |
|
sl@0
|
1398 |
iSnkBufRef and iSrcBufRef contain ETrue if these buffers are created and owned by a MDataSource or MDataSink
|
sl@0
|
1399 |
For clean-up purposes, datapath only cleans up buffers allocated directly by PrimeL().
|
sl@0
|
1400 |
*/
|
sl@0
|
1401 |
|
sl@0
|
1402 |
EXPORT_C void CMMFDataPath::PrimeL()
|
sl@0
|
1403 |
{
|
sl@0
|
1404 |
#ifdef _DP_DEBUG
|
sl@0
|
1405 |
RDebug::Print(_L("DP::PrimeL tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1406 |
#endif
|
sl@0
|
1407 |
|
sl@0
|
1408 |
//allocate resources ie buffers & prepare to play
|
sl@0
|
1409 |
if (iDataPathCreated && (iState == EStopped))
|
sl@0
|
1410 |
//luckily the client utility does this.
|
sl@0
|
1411 |
{//can only prime from the stopped state
|
sl@0
|
1412 |
|
sl@0
|
1413 |
//This will determine what buffers we need to run the datapath.
|
sl@0
|
1414 |
//Can leave KERRNotSupported
|
sl@0
|
1415 |
iBuffersToUse = DetermineBuffersToUseL();
|
sl@0
|
1416 |
|
sl@0
|
1417 |
//Try to create source and sink buffers. If we can't create them in the Prime,
|
sl@0
|
1418 |
//we will need to obtain them by asynchronous buffer creation when playing starts.
|
sl@0
|
1419 |
ObtainSyncBuffersL();
|
sl@0
|
1420 |
|
sl@0
|
1421 |
iDataSource->SourcePrimeL(); //propogate state change to source
|
sl@0
|
1422 |
iDataSink->SinkPrimeL(); //propogate state change to sink
|
sl@0
|
1423 |
|
sl@0
|
1424 |
|
sl@0
|
1425 |
//If Client has set these, they will be set following the prime
|
sl@0
|
1426 |
iPlayWindowStartPosition = 0;
|
sl@0
|
1427 |
iPlayWindowEndPosition = Duration();
|
sl@0
|
1428 |
|
sl@0
|
1429 |
iState = EPrimed;
|
sl@0
|
1430 |
iPauseCalled = EFalse;
|
sl@0
|
1431 |
|
sl@0
|
1432 |
if (iCompleteCallback)
|
sl@0
|
1433 |
{
|
sl@0
|
1434 |
delete iCompleteCallback;
|
sl@0
|
1435 |
iCompleteCallback = NULL;
|
sl@0
|
1436 |
}
|
sl@0
|
1437 |
TBool waitForSink = (iDataSink->DataSinkType() == KUidMmfAudioOutput)?ETrue:EFalse;
|
sl@0
|
1438 |
iCompleteCallback = new (ELeave) CCompleteCallback(*this,waitForSink);
|
sl@0
|
1439 |
}
|
sl@0
|
1440 |
#ifdef _DP_DEBUG
|
sl@0
|
1441 |
RDebug::Print(_L("DP::PrimeL Done tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1442 |
#endif
|
sl@0
|
1443 |
}
|
sl@0
|
1444 |
|
sl@0
|
1445 |
|
sl@0
|
1446 |
/**
|
sl@0
|
1447 |
Starts an active scheduler 'play' loop.
|
sl@0
|
1448 |
|
sl@0
|
1449 |
Can only play from the primed state.
|
sl@0
|
1450 |
*/
|
sl@0
|
1451 |
EXPORT_C void CMMFDataPath::PlayL()
|
sl@0
|
1452 |
{
|
sl@0
|
1453 |
#if defined(__PROFILING)
|
sl@0
|
1454 |
RDebug::ProfileEnd(1);
|
sl@0
|
1455 |
#endif // defined(__PROFILING)
|
sl@0
|
1456 |
|
sl@0
|
1457 |
#ifdef _DP_DEBUG
|
sl@0
|
1458 |
RDebug::Print(_L("DP::PlayL, on src buff %d sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);
|
sl@0
|
1459 |
RDebug::Print(_L("iStartPosition = %d\n"), I64INT(iStartPosition.Int64()));
|
sl@0
|
1460 |
#endif
|
sl@0
|
1461 |
|
sl@0
|
1462 |
if ((iDataPathCreated) && (iState == EPrimed))
|
sl@0
|
1463 |
{
|
sl@0
|
1464 |
//can only play from the primed state
|
sl@0
|
1465 |
|
sl@0
|
1466 |
TBool savedPauseCalled=EFalse;
|
sl@0
|
1467 |
if(iPauseCalled) //sink and source will have been stopped, and we will not have been re-primed
|
sl@0
|
1468 |
{
|
sl@0
|
1469 |
savedPauseCalled=ETrue;
|
sl@0
|
1470 |
iDataSink->SinkPrimeL(); //propagate change down to sink
|
sl@0
|
1471 |
iPauseCalled = EFalse;
|
sl@0
|
1472 |
}
|
sl@0
|
1473 |
|
sl@0
|
1474 |
iCurrentSourceFrameNumber = 0; //reset to beginning
|
sl@0
|
1475 |
iCurrentSinkFrameNumber = 0; //reset to beginning
|
sl@0
|
1476 |
|
sl@0
|
1477 |
iSourceBufferWithSource = EFalse;
|
sl@0
|
1478 |
iSinkBufferWithSink = EFalse;
|
sl@0
|
1479 |
|
sl@0
|
1480 |
iNoMoreSourceData = EFalse;
|
sl@0
|
1481 |
iAllDataSentToSink=EFalse;
|
sl@0
|
1482 |
iDataPathCompletedErrorCode=KErrNone;
|
sl@0
|
1483 |
|
sl@0
|
1484 |
SetPositionL( iStartPosition ) ;
|
sl@0
|
1485 |
iReferenceAudioSamplesPlayed = 0;
|
sl@0
|
1486 |
iReferenceAudioSamplesRecorded = 0;
|
sl@0
|
1487 |
|
sl@0
|
1488 |
//complete a request on iStatus to invoke play code
|
sl@0
|
1489 |
iDataSource->SourcePlayL(); //propagate state change to source
|
sl@0
|
1490 |
if (!(savedPauseCalled && (iTransferState==EWaitSink || iTransferState==EInitializeSink)))
|
sl@0
|
1491 |
{
|
sl@0
|
1492 |
iDataSink->SinkPlayL(); //propogate state change to sink
|
sl@0
|
1493 |
}
|
sl@0
|
1494 |
|
sl@0
|
1495 |
if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
|
sl@0
|
1496 |
iState = EPlaying;
|
sl@0
|
1497 |
else if(iDataSource->DataSourceType() == KUidMmfAudioInput)
|
sl@0
|
1498 |
iState = ERecording;
|
sl@0
|
1499 |
else
|
sl@0
|
1500 |
iState = EConverting;
|
sl@0
|
1501 |
|
sl@0
|
1502 |
//need to re-initialize any buffer(s) that we only own references to
|
sl@0
|
1503 |
ChangeDataPathTransferState(EInitializeSink);
|
sl@0
|
1504 |
}
|
sl@0
|
1505 |
#ifdef _DP_DEBUG
|
sl@0
|
1506 |
RDebug::Print(_L("DP::Play - DONE\n"));
|
sl@0
|
1507 |
#endif
|
sl@0
|
1508 |
}
|
sl@0
|
1509 |
|
sl@0
|
1510 |
|
sl@0
|
1511 |
/**
|
sl@0
|
1512 |
Pauses playing.
|
sl@0
|
1513 |
|
sl@0
|
1514 |
Sends KMMFErrorCategoryDataPathGeneralError to the client if an error occurs.
|
sl@0
|
1515 |
*/
|
sl@0
|
1516 |
EXPORT_C void CMMFDataPath::Pause()
|
sl@0
|
1517 |
{
|
sl@0
|
1518 |
#ifdef _DP_DEBUG
|
sl@0
|
1519 |
RDebug::Print(_L("DP::Pause, on src buff %d sink buf %d (this 0x%x)\n"), iCurrentSourceFrameNumber, iCurrentSinkFrameNumber,this);
|
sl@0
|
1520 |
RDebug::Print(_L("DP::Pause current state=%d tick-%d (this 0x%x)\n"),iTransferState, User::TickCount(),this);
|
sl@0
|
1521 |
#endif
|
sl@0
|
1522 |
|
sl@0
|
1523 |
TRAPD(err, DoPauseL());
|
sl@0
|
1524 |
|
sl@0
|
1525 |
if (err)
|
sl@0
|
1526 |
{
|
sl@0
|
1527 |
DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
|
sl@0
|
1528 |
}
|
sl@0
|
1529 |
#ifdef _DP_DEBUG
|
sl@0
|
1530 |
RDebug::Print(_L("DP::Pause - DONE tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1531 |
#endif
|
sl@0
|
1532 |
}
|
sl@0
|
1533 |
|
sl@0
|
1534 |
/**
|
sl@0
|
1535 |
Stops playing.
|
sl@0
|
1536 |
|
sl@0
|
1537 |
Resets datapath position - currently does not clean up buffers. Sends KMMFErrorCategoryDataPathGeneralError
|
sl@0
|
1538 |
to the client if an error occurs.
|
sl@0
|
1539 |
*/
|
sl@0
|
1540 |
EXPORT_C void CMMFDataPath::Stop()
|
sl@0
|
1541 |
{
|
sl@0
|
1542 |
#ifdef _DP_DEBUG
|
sl@0
|
1543 |
RDebug::Print(_L("DP::Stop current state=%d tick-%d (this 0x%x)\n"), iTransferState, User::TickCount(),this);
|
sl@0
|
1544 |
#endif
|
sl@0
|
1545 |
|
sl@0
|
1546 |
if ((iDataPathCreated) && (iState != EStopped))
|
sl@0
|
1547 |
{
|
sl@0
|
1548 |
TRAPD(err, DoStopL());
|
sl@0
|
1549 |
|
sl@0
|
1550 |
if (err)
|
sl@0
|
1551 |
DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
|
sl@0
|
1552 |
}
|
sl@0
|
1553 |
}
|
sl@0
|
1554 |
/**
|
sl@0
|
1555 |
Forces and end of data state on the datapath
|
sl@0
|
1556 |
*/
|
sl@0
|
1557 |
EXPORT_C void CMMFDataPath::EndOfData()
|
sl@0
|
1558 |
{
|
sl@0
|
1559 |
TRAPD(err, DoEndOfDataL());
|
sl@0
|
1560 |
|
sl@0
|
1561 |
if (err)
|
sl@0
|
1562 |
{
|
sl@0
|
1563 |
DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, err);
|
sl@0
|
1564 |
}
|
sl@0
|
1565 |
}
|
sl@0
|
1566 |
|
sl@0
|
1567 |
/**
|
sl@0
|
1568 |
|
sl@0
|
1569 |
*/
|
sl@0
|
1570 |
TInt CMMFDataPath::AudioSamplesPlayed() const
|
sl@0
|
1571 |
{
|
sl@0
|
1572 |
if (iDataSink->DataSinkType() != KUidMmfAudioOutput)
|
sl@0
|
1573 |
return 0;
|
sl@0
|
1574 |
|
sl@0
|
1575 |
CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
|
sl@0
|
1576 |
|
sl@0
|
1577 |
TInt samples = 0;
|
sl@0
|
1578 |
|
sl@0
|
1579 |
if(iState == EPlaying)
|
sl@0
|
1580 |
samples = audioOutput->SoundDevice().SamplesPlayed();
|
sl@0
|
1581 |
|
sl@0
|
1582 |
#ifdef _DP_DEBUG
|
sl@0
|
1583 |
RDebug::Print(_L("DP::AudioSamplesPlayed = %d\n"),samples);
|
sl@0
|
1584 |
#endif
|
sl@0
|
1585 |
|
sl@0
|
1586 |
return samples;
|
sl@0
|
1587 |
}
|
sl@0
|
1588 |
|
sl@0
|
1589 |
|
sl@0
|
1590 |
/**
|
sl@0
|
1591 |
|
sl@0
|
1592 |
*/
|
sl@0
|
1593 |
TInt CMMFDataPath::AudioSamplesRecorded() const
|
sl@0
|
1594 |
{
|
sl@0
|
1595 |
if (iDataSource->DataSourceType() != KUidMmfAudioInput)
|
sl@0
|
1596 |
return 0;
|
sl@0
|
1597 |
|
sl@0
|
1598 |
CMMFAudioInput* audioInput = STATIC_CAST(CMMFAudioInput*,iDataSource);
|
sl@0
|
1599 |
|
sl@0
|
1600 |
TInt samples = 0;
|
sl@0
|
1601 |
|
sl@0
|
1602 |
if(iState == ERecording)
|
sl@0
|
1603 |
samples = audioInput->SoundDevice().SamplesRecorded();
|
sl@0
|
1604 |
|
sl@0
|
1605 |
#ifdef _DP_DEBUG
|
sl@0
|
1606 |
RDebug::Print(_L("DP::AudioSamplesRecorded = %d\n"),samples);
|
sl@0
|
1607 |
#endif
|
sl@0
|
1608 |
|
sl@0
|
1609 |
return samples;
|
sl@0
|
1610 |
}
|
sl@0
|
1611 |
|
sl@0
|
1612 |
|
sl@0
|
1613 |
/**
|
sl@0
|
1614 |
|
sl@0
|
1615 |
*/
|
sl@0
|
1616 |
TTimeIntervalMicroSeconds CMMFDataPath::CalculateAudioOutputPosition() const
|
sl@0
|
1617 |
{
|
sl@0
|
1618 |
//This operation can only be carried out on an Audio Output
|
sl@0
|
1619 |
__ASSERT_ALWAYS(iDataSink->DataSinkType() == KUidMmfAudioOutput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
|
sl@0
|
1620 |
|
sl@0
|
1621 |
|
sl@0
|
1622 |
//If we are not playing, simply return where we will play from
|
sl@0
|
1623 |
if(iState != EPlaying || iCurrentSinkFrameNumber == 0)
|
sl@0
|
1624 |
return iStartPosition;
|
sl@0
|
1625 |
|
sl@0
|
1626 |
#ifdef _DP_DEBUG
|
sl@0
|
1627 |
RDebug::Print(_L("DP::CalculateAudioOutputDuration from %d\n"),iReferenceAudioSamplesPlayed);
|
sl@0
|
1628 |
#endif
|
sl@0
|
1629 |
|
sl@0
|
1630 |
TReal samplesPlayed = AudioSamplesPlayed() - iReferenceAudioSamplesPlayed;
|
sl@0
|
1631 |
|
sl@0
|
1632 |
CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*,iDataSink);
|
sl@0
|
1633 |
CMMFDevSound& devSound = audioOutput->SoundDevice();
|
sl@0
|
1634 |
|
sl@0
|
1635 |
TMMFCapabilities devSoundConfig = devSound.Config();
|
sl@0
|
1636 |
|
sl@0
|
1637 |
TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
|
sl@0
|
1638 |
|
sl@0
|
1639 |
#ifdef _DP_DEBUG
|
sl@0
|
1640 |
RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
|
sl@0
|
1641 |
#endif
|
sl@0
|
1642 |
|
sl@0
|
1643 |
TReal timePlayedSeconds = 0;
|
sl@0
|
1644 |
if(samplesPlayed)
|
sl@0
|
1645 |
timePlayedSeconds = samplesPlayed/samplingFreq;
|
sl@0
|
1646 |
|
sl@0
|
1647 |
TInt64 timePlayed(I64DOUBLECAST(timePlayedSeconds * 1000000));
|
sl@0
|
1648 |
|
sl@0
|
1649 |
#ifdef _DP_DEBUG
|
sl@0
|
1650 |
RDebug::Print(_L("timePlayed %d\n"), I64LOW(timePlayed));
|
sl@0
|
1651 |
#endif
|
sl@0
|
1652 |
|
sl@0
|
1653 |
return TTimeIntervalMicroSeconds(timePlayed + iStartPosition.Int64());
|
sl@0
|
1654 |
}
|
sl@0
|
1655 |
|
sl@0
|
1656 |
|
sl@0
|
1657 |
|
sl@0
|
1658 |
/**
|
sl@0
|
1659 |
|
sl@0
|
1660 |
*/
|
sl@0
|
1661 |
TTimeIntervalMicroSeconds CMMFDataPath::CalculateAudioInputPosition() const
|
sl@0
|
1662 |
{
|
sl@0
|
1663 |
//This operation can only be carried out on an Audio Input
|
sl@0
|
1664 |
__ASSERT_ALWAYS(iDataSource->DataSourceType() == KUidMmfAudioInput, Panic(EMMFDataPathPanicProgrammingError,__LINE__));
|
sl@0
|
1665 |
|
sl@0
|
1666 |
|
sl@0
|
1667 |
//If we are not playing, simply return where we will play from
|
sl@0
|
1668 |
if(iState != ERecording)
|
sl@0
|
1669 |
return iStartPosition;
|
sl@0
|
1670 |
|
sl@0
|
1671 |
#ifdef _DP_DEBUG
|
sl@0
|
1672 |
RDebug::Print(_L("DP::CalculateAudioInputPosition from %d\n"),iReferenceAudioSamplesRecorded);
|
sl@0
|
1673 |
#endif
|
sl@0
|
1674 |
|
sl@0
|
1675 |
TReal samplesRecorded = AudioSamplesRecorded() - iReferenceAudioSamplesRecorded;
|
sl@0
|
1676 |
|
sl@0
|
1677 |
CMMFAudioInput* audioInput = STATIC_CAST(CMMFAudioInput*,iDataSource);
|
sl@0
|
1678 |
CMMFDevSound& devSound = audioInput->SoundDevice();
|
sl@0
|
1679 |
|
sl@0
|
1680 |
TMMFCapabilities devSoundConfig = devSound.Config();
|
sl@0
|
1681 |
|
sl@0
|
1682 |
TInt samplingFreq = StreamUtils::SampleRateAsValue(devSoundConfig);
|
sl@0
|
1683 |
|
sl@0
|
1684 |
#ifdef _DP_DEBUG
|
sl@0
|
1685 |
RDebug::Print(_L("samplingFreq %d\n"),samplingFreq);
|
sl@0
|
1686 |
#endif
|
sl@0
|
1687 |
|
sl@0
|
1688 |
TReal timeRecordedSeconds = 0;
|
sl@0
|
1689 |
if(samplesRecorded)
|
sl@0
|
1690 |
timeRecordedSeconds = samplesRecorded/samplingFreq;
|
sl@0
|
1691 |
|
sl@0
|
1692 |
TInt64 timeRecorded(I64DOUBLECAST(timeRecordedSeconds * 1000000));
|
sl@0
|
1693 |
|
sl@0
|
1694 |
#ifdef _DP_DEBUG
|
sl@0
|
1695 |
RDebug::Print(_L("timeRecorded %d\n"), I64LOW(timeRecorded));
|
sl@0
|
1696 |
#endif
|
sl@0
|
1697 |
return TTimeIntervalMicroSeconds(timeRecorded);
|
sl@0
|
1698 |
}
|
sl@0
|
1699 |
|
sl@0
|
1700 |
|
sl@0
|
1701 |
|
sl@0
|
1702 |
|
sl@0
|
1703 |
|
sl@0
|
1704 |
TTimeIntervalMicroSeconds CMMFDataPath::OutputPosition() const
|
sl@0
|
1705 |
{
|
sl@0
|
1706 |
TTimeIntervalMicroSeconds interval;
|
sl@0
|
1707 |
TTimeIntervalMicroSeconds position;
|
sl@0
|
1708 |
|
sl@0
|
1709 |
if (iDataSink->DataSinkType() == KUidMmfAudioOutput)
|
sl@0
|
1710 |
{
|
sl@0
|
1711 |
position = CalculateAudioOutputPosition();
|
sl@0
|
1712 |
#ifdef _DP_DEBUG
|
sl@0
|
1713 |
RDebug::Print(_L("DP::OutputPosition from audio output= %d\n"),I64INT(position.Int64()));
|
sl@0
|
1714 |
#endif
|
sl@0
|
1715 |
}
|
sl@0
|
1716 |
else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
|
sl@0
|
1717 |
{
|
sl@0
|
1718 |
//note Encode format position takes priority if both source & sink are formats?
|
sl@0
|
1719 |
// try to get the position directly from the format. If that fails, work it out here
|
sl@0
|
1720 |
TRAPD(error, position = ((CMMFFormatEncode*)iDataSink)->PositionL());
|
sl@0
|
1721 |
if (error)//getting the position from the format didn't work so calculate it here
|
sl@0
|
1722 |
{
|
sl@0
|
1723 |
interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
|
sl@0
|
1724 |
TInt64 position64 = interval.Int64() * iCurrentSinkFrameNumber;
|
sl@0
|
1725 |
position = position64;
|
sl@0
|
1726 |
}
|
sl@0
|
1727 |
|
sl@0
|
1728 |
TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath*,this)->Duration(); //need this to check position doesn't exceed duration
|
sl@0
|
1729 |
if (position > duration)//this can happen on last buffer
|
sl@0
|
1730 |
position = duration;
|
sl@0
|
1731 |
|
sl@0
|
1732 |
|
sl@0
|
1733 |
#ifdef _DP_DEBUG
|
sl@0
|
1734 |
RDebug::Print(_L("DP::OutputPosition from format= %d\n"),I64INT(position.Int64()));
|
sl@0
|
1735 |
#endif
|
sl@0
|
1736 |
}
|
sl@0
|
1737 |
else
|
sl@0
|
1738 |
{//can only read output position if sink is a format or an audio output
|
sl@0
|
1739 |
return TTimeIntervalMicroSeconds(0);
|
sl@0
|
1740 |
}
|
sl@0
|
1741 |
|
sl@0
|
1742 |
return position;
|
sl@0
|
1743 |
}
|
sl@0
|
1744 |
|
sl@0
|
1745 |
TTimeIntervalMicroSeconds CMMFDataPath::InputPosition() const
|
sl@0
|
1746 |
{
|
sl@0
|
1747 |
TTimeIntervalMicroSeconds interval;
|
sl@0
|
1748 |
TTimeIntervalMicroSeconds position;
|
sl@0
|
1749 |
|
sl@0
|
1750 |
if (iDataSource->DataSourceType() == KUidMmfAudioInput)
|
sl@0
|
1751 |
{
|
sl@0
|
1752 |
position = CalculateAudioInputPosition();
|
sl@0
|
1753 |
#ifdef _DP_DEBUG
|
sl@0
|
1754 |
RDebug::Print(_L("DP::InputPosition from audio input= %d\n"),I64INT(position.Int64()));
|
sl@0
|
1755 |
#endif
|
sl@0
|
1756 |
}
|
sl@0
|
1757 |
else if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
|
sl@0
|
1758 |
{//note Decode format position takes priority if both source & sink are formats?
|
sl@0
|
1759 |
// try to get the position directly from the format. If that fails, work it out here
|
sl@0
|
1760 |
TRAPD(error, position = ((CMMFFormatDecode*)iDataSource)->PositionL());
|
sl@0
|
1761 |
if (error)//getting the position from the format didn't work so calculate it here
|
sl@0
|
1762 |
{
|
sl@0
|
1763 |
interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
|
sl@0
|
1764 |
TInt64 position64 = interval.Int64() * iCurrentSourceFrameNumber;
|
sl@0
|
1765 |
position = position64;
|
sl@0
|
1766 |
}
|
sl@0
|
1767 |
|
sl@0
|
1768 |
TTimeIntervalMicroSeconds duration = CONST_CAST(CMMFDataPath*,this)->Duration(); //need this to check position doesn't exceed duration
|
sl@0
|
1769 |
if (position > duration)//this can happen on last buffer
|
sl@0
|
1770 |
position = duration;
|
sl@0
|
1771 |
|
sl@0
|
1772 |
#ifdef _DP_DEBUG
|
sl@0
|
1773 |
RDebug::Print(_L("DP::InputPosition from format = %d\n"),I64INT(position.Int64()));
|
sl@0
|
1774 |
#endif
|
sl@0
|
1775 |
}
|
sl@0
|
1776 |
else
|
sl@0
|
1777 |
{//can only read input position if source is a format or an audio input
|
sl@0
|
1778 |
return TTimeIntervalMicroSeconds(0);
|
sl@0
|
1779 |
}
|
sl@0
|
1780 |
|
sl@0
|
1781 |
return position;
|
sl@0
|
1782 |
}
|
sl@0
|
1783 |
|
sl@0
|
1784 |
|
sl@0
|
1785 |
|
sl@0
|
1786 |
|
sl@0
|
1787 |
/**
|
sl@0
|
1788 |
Gets the data path position.
|
sl@0
|
1789 |
|
sl@0
|
1790 |
@return The data path position.
|
sl@0
|
1791 |
*/
|
sl@0
|
1792 |
EXPORT_C TTimeIntervalMicroSeconds CMMFDataPath::Position() const
|
sl@0
|
1793 |
{
|
sl@0
|
1794 |
if ((iState == ERecording) || (iState == EConverting))
|
sl@0
|
1795 |
return InputPosition();
|
sl@0
|
1796 |
else if(iState == EPlaying)
|
sl@0
|
1797 |
return OutputPosition();
|
sl@0
|
1798 |
else
|
sl@0
|
1799 |
{
|
sl@0
|
1800 |
return iStartPosition;
|
sl@0
|
1801 |
}
|
sl@0
|
1802 |
}
|
sl@0
|
1803 |
|
sl@0
|
1804 |
/**
|
sl@0
|
1805 |
Sets the data path position.
|
sl@0
|
1806 |
|
sl@0
|
1807 |
@param aPosition
|
sl@0
|
1808 |
The data path position.
|
sl@0
|
1809 |
*/
|
sl@0
|
1810 |
EXPORT_C void CMMFDataPath::SetPositionL(const TTimeIntervalMicroSeconds& aPosition)
|
sl@0
|
1811 |
{//need to map to source position to frame position
|
sl@0
|
1812 |
#ifdef _DP_DEBUG
|
sl@0
|
1813 |
RDebug::Print(_L("DP::SetPositionL = %d ticks-%d (this 0x%x)\n"),I64INT(aPosition.Int64()), User::TickCount(),this);
|
sl@0
|
1814 |
#endif
|
sl@0
|
1815 |
|
sl@0
|
1816 |
if (iState == EStopped)
|
sl@0
|
1817 |
User::Leave(KErrNotReady); //can only set position if primed
|
sl@0
|
1818 |
|
sl@0
|
1819 |
//As this will affect the position, we need to know how many bytes were
|
sl@0
|
1820 |
//played when position was updated. Future Position() requests will
|
sl@0
|
1821 |
//then use this refernce to determine the current position.
|
sl@0
|
1822 |
iReferenceAudioSamplesPlayed = AudioSamplesPlayed();
|
sl@0
|
1823 |
|
sl@0
|
1824 |
// Force the new position to be inside the play window (also within the file duration)
|
sl@0
|
1825 |
if ( aPosition < iPlayWindowStartPosition )
|
sl@0
|
1826 |
iStartPosition = iPlayWindowStartPosition;
|
sl@0
|
1827 |
else if ( aPosition > iPlayWindowEndPosition )
|
sl@0
|
1828 |
iStartPosition = iPlayWindowEndPosition; //clearly this will cause nothing to be played
|
sl@0
|
1829 |
else
|
sl@0
|
1830 |
iStartPosition = aPosition;
|
sl@0
|
1831 |
|
sl@0
|
1832 |
TTimeIntervalMicroSeconds interval;
|
sl@0
|
1833 |
|
sl@0
|
1834 |
//can only set the position on an MDataSource that is a format object
|
sl@0
|
1835 |
//Note: position defaults to source if both source & sink are clips
|
sl@0
|
1836 |
if (iDataSource->DataSourceType() == KUidMmfFormatDecode)
|
sl@0
|
1837 |
{
|
sl@0
|
1838 |
//position is not beyond the end of file
|
sl@0
|
1839 |
interval = ((CMMFFormatDecode*)iDataSource)->FrameTimeInterval(iMediaId);
|
sl@0
|
1840 |
|
sl@0
|
1841 |
// for some reason this code won't compile without these intermediate steps
|
sl@0
|
1842 |
TInt64 position = iStartPosition.Int64();
|
sl@0
|
1843 |
TInt64 interval64 = interval.Int64();
|
sl@0
|
1844 |
if (interval64 == 0)
|
sl@0
|
1845 |
User::Leave(KErrDivideByZero);
|
sl@0
|
1846 |
TInt64 datapos64 = position/interval64;
|
sl@0
|
1847 |
iCurrentSourceFrameNumber = I64LOW(datapos64);
|
sl@0
|
1848 |
|
sl@0
|
1849 |
|
sl@0
|
1850 |
// Try to set the position directly on the format
|
sl@0
|
1851 |
TRAP_IGNORE(((CMMFFormatDecode*)iDataSource)->SetPositionL(iStartPosition));
|
sl@0
|
1852 |
//NB: don't worry about error, since we'll reposition anyway when we get the next buffer
|
sl@0
|
1853 |
}
|
sl@0
|
1854 |
else if (iDataSink->DataSinkType() == KUidMmfFormatEncode)
|
sl@0
|
1855 |
{
|
sl@0
|
1856 |
//position is not beyond the end of file
|
sl@0
|
1857 |
interval = ((CMMFFormatEncode*)iDataSink)->FrameTimeInterval(iMediaId);
|
sl@0
|
1858 |
|
sl@0
|
1859 |
//convert to TUint - for some reason it won't compile without these intermediate steps
|
sl@0
|
1860 |
TInt64 position = iStartPosition.Int64();
|
sl@0
|
1861 |
TInt64 interval64 = interval.Int64();
|
sl@0
|
1862 |
if (interval64 == 0)
|
sl@0
|
1863 |
User::Leave(KErrDivideByZero);
|
sl@0
|
1864 |
TInt64 datapos64 = position/interval64;
|
sl@0
|
1865 |
iCurrentSinkFrameNumber = I64LOW(datapos64);
|
sl@0
|
1866 |
|
sl@0
|
1867 |
|
sl@0
|
1868 |
// Try to set the position directly on the format
|
sl@0
|
1869 |
TRAP_IGNORE(((CMMFFormatEncode*)iDataSink)->SetPositionL(iStartPosition));
|
sl@0
|
1870 |
//NB: don't worry about error, since we'll reposition anyway when we get the next buffer
|
sl@0
|
1871 |
}
|
sl@0
|
1872 |
else
|
sl@0
|
1873 |
{//can only set position if source or sink is a format
|
sl@0
|
1874 |
//If both source and sink are formats position is relative to the source
|
sl@0
|
1875 |
User::Leave(KErrNotSupported); //can't set position if neither source nor sink are clips
|
sl@0
|
1876 |
}
|
sl@0
|
1877 |
|
sl@0
|
1878 |
if(iCodec) //we have a real codec, must reset it
|
sl@0
|
1879 |
iCodec->ResetL(); // Need to preserve sync when resuming play
|
sl@0
|
1880 |
|
sl@0
|
1881 |
// Once we've sent the last buffer to the sink it's too late to start
|
sl@0
|
1882 |
// changing the state since we may get a RunError(KErrUnderflow) at any time.
|
sl@0
|
1883 |
// Once this happens, the sound driver may have unloaded etc..and recovery
|
sl@0
|
1884 |
// would be complicated.
|
sl@0
|
1885 |
if (iAllDataSentToSink)
|
sl@0
|
1886 |
return;
|
sl@0
|
1887 |
|
sl@0
|
1888 |
#ifdef _DP_DEBUG
|
sl@0
|
1889 |
RDebug::Print(_L("DP::SetPosition - Done iCurrentSourceFrameNumber=%d iStartPosition=%d ticks-%d (this 0x%x)\n"),iCurrentSourceFrameNumber, I64INT(iStartPosition.Int64()), User::TickCount(),this);
|
sl@0
|
1890 |
#endif
|
sl@0
|
1891 |
}
|
sl@0
|
1892 |
|
sl@0
|
1893 |
|
sl@0
|
1894 |
|
sl@0
|
1895 |
|
sl@0
|
1896 |
/**
|
sl@0
|
1897 |
Sets the play window absolutely (i.e. the parameters are relative to the start of the entire clip).
|
sl@0
|
1898 |
|
sl@0
|
1899 |
@param aStart
|
sl@0
|
1900 |
The offset from the start of the Clip
|
sl@0
|
1901 |
@param aEnd
|
sl@0
|
1902 |
The offset from the end of the clip (if this is less than aStart, then the two will be inverted).
|
sl@0
|
1903 |
*/
|
sl@0
|
1904 |
EXPORT_C void CMMFDataPath::SetPlayWindowL( const TTimeIntervalMicroSeconds& aStart, const TTimeIntervalMicroSeconds& aEnd )
|
sl@0
|
1905 |
{
|
sl@0
|
1906 |
// Clear the existing Play window
|
sl@0
|
1907 |
ClearPlayWindowL() ;
|
sl@0
|
1908 |
|
sl@0
|
1909 |
// Check that the parameters are legitimate. 0 <= startpos < endpos <= duration & update member variables
|
sl@0
|
1910 |
TTimeIntervalMicroSeconds duration = Duration();
|
sl@0
|
1911 |
|
sl@0
|
1912 |
if ( aStart < TTimeIntervalMicroSeconds(0) )
|
sl@0
|
1913 |
iPlayWindowStartPosition = TTimeIntervalMicroSeconds(0);
|
sl@0
|
1914 |
else if ( aStart > duration )
|
sl@0
|
1915 |
iPlayWindowStartPosition = duration;
|
sl@0
|
1916 |
else iPlayWindowStartPosition = aStart;
|
sl@0
|
1917 |
|
sl@0
|
1918 |
if ( aEnd < TTimeIntervalMicroSeconds(0) )
|
sl@0
|
1919 |
iPlayWindowEndPosition = TTimeIntervalMicroSeconds(0);
|
sl@0
|
1920 |
else if ( aEnd > duration )
|
sl@0
|
1921 |
iPlayWindowEndPosition = duration;
|
sl@0
|
1922 |
else iPlayWindowEndPosition = aEnd;
|
sl@0
|
1923 |
|
sl@0
|
1924 |
// ensure that the current position is inside the new play window
|
sl@0
|
1925 |
if ( iPlayWindowEndPosition != TTimeIntervalMicroSeconds(0) )
|
sl@0
|
1926 |
{
|
sl@0
|
1927 |
TTimeIntervalMicroSeconds currentPosition = Position() ;
|
sl@0
|
1928 |
if ( currentPosition < iPlayWindowStartPosition )
|
sl@0
|
1929 |
SetPositionL( iPlayWindowStartPosition ) ;
|
sl@0
|
1930 |
else if ( currentPosition > iPlayWindowEndPosition )
|
sl@0
|
1931 |
SetPositionL( iPlayWindowEndPosition ) ;
|
sl@0
|
1932 |
}
|
sl@0
|
1933 |
else
|
sl@0
|
1934 |
ClearPlayWindowL() ;
|
sl@0
|
1935 |
|
sl@0
|
1936 |
#ifdef _DP_DEBUG
|
sl@0
|
1937 |
RDebug::Print(_L("DP::SetPlayWindowL iPlayWindowStartPosition=%d iPlayWindowEndPosition=%d\n"),I64INT(iPlayWindowStartPosition.Int64()),I64INT(iPlayWindowEndPosition.Int64()));
|
sl@0
|
1938 |
#endif
|
sl@0
|
1939 |
}
|
sl@0
|
1940 |
|
sl@0
|
1941 |
|
sl@0
|
1942 |
/**
|
sl@0
|
1943 |
Sets the play window to the full length of clip.
|
sl@0
|
1944 |
*/
|
sl@0
|
1945 |
EXPORT_C void CMMFDataPath::ClearPlayWindowL()
|
sl@0
|
1946 |
{
|
sl@0
|
1947 |
iPlayWindowStartPosition = TTimeIntervalMicroSeconds(0) ;
|
sl@0
|
1948 |
iPlayWindowEndPosition = Duration();
|
sl@0
|
1949 |
|
sl@0
|
1950 |
|
sl@0
|
1951 |
if(iState == EStopped)
|
sl@0
|
1952 |
iStartPosition = iPlayWindowStartPosition;
|
sl@0
|
1953 |
}
|
sl@0
|
1954 |
|
sl@0
|
1955 |
/**
|
sl@0
|
1956 |
Returns the current data path state.
|
sl@0
|
1957 |
*/
|
sl@0
|
1958 |
EXPORT_C TInt CMMFDataPath::State()
|
sl@0
|
1959 |
{
|
sl@0
|
1960 |
return iState ;
|
sl@0
|
1961 |
}
|
sl@0
|
1962 |
|
sl@0
|
1963 |
|
sl@0
|
1964 |
/**
|
sl@0
|
1965 |
Uses the AO mechanism to drive state changes between sources and sinks.
|
sl@0
|
1966 |
|
sl@0
|
1967 |
RunL() moves and assigns buffers between its attached MDataSource/MDataSinks.
|
sl@0
|
1968 |
*/
|
sl@0
|
1969 |
void CMMFDataPath::ChangeDataPathTransferState(TTransferState aNewDataPathTransferState)
|
sl@0
|
1970 |
{
|
sl@0
|
1971 |
#ifdef _DP_DEBUG
|
sl@0
|
1972 |
switch (aNewDataPathTransferState)
|
sl@0
|
1973 |
{
|
sl@0
|
1974 |
case EWaitSink:
|
sl@0
|
1975 |
RDebug::Print(_L("Next State EWaitSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1976 |
break;
|
sl@0
|
1977 |
case EWaitSource:
|
sl@0
|
1978 |
RDebug::Print(_L("Next State EWaitSource ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1979 |
break;
|
sl@0
|
1980 |
case EInitializeSink:
|
sl@0
|
1981 |
RDebug::Print(_L("Next State EInitializeSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1982 |
break;
|
sl@0
|
1983 |
case EInitializeSource:
|
sl@0
|
1984 |
RDebug::Print(_L("Next State EInitializeSource ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1985 |
break;
|
sl@0
|
1986 |
case ENeedSourceData:
|
sl@0
|
1987 |
RDebug::Print(_L("Next State ENeedSourceData ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1988 |
break;
|
sl@0
|
1989 |
case ENeedSinkData:
|
sl@0
|
1990 |
RDebug::Print(_L("Next State ENeedSinkData ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1991 |
break;
|
sl@0
|
1992 |
case ENeedToMatchSourceToSink:
|
sl@0
|
1993 |
RDebug::Print(_L("Next State ENeedToMatchSourceToSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1994 |
break;
|
sl@0
|
1995 |
case ESendDataToSink:
|
sl@0
|
1996 |
RDebug::Print(_L("Next State ESendDataToSink ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
1997 |
break;
|
sl@0
|
1998 |
case EEndOfData:
|
sl@0
|
1999 |
RDebug::Print(_L("Next State EEndOfData ticks-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
2000 |
break;
|
sl@0
|
2001 |
}
|
sl@0
|
2002 |
#endif
|
sl@0
|
2003 |
|
sl@0
|
2004 |
|
sl@0
|
2005 |
TRequestStatus* stat = &iStatus;
|
sl@0
|
2006 |
//change state
|
sl@0
|
2007 |
iTransferState = aNewDataPathTransferState;
|
sl@0
|
2008 |
if ((iTransferState != EWaitSink) && (iTransferState != EWaitSource) &&
|
sl@0
|
2009 |
(iState == EPlaying || iState == ERecording || iState == EConverting || (iState == EPrimed && iPauseCalled)))
|
sl@0
|
2010 |
{//can go ahead with transfer
|
sl@0
|
2011 |
if (!IsActive())
|
sl@0
|
2012 |
{
|
sl@0
|
2013 |
User::RequestComplete(stat, KErrNone);
|
sl@0
|
2014 |
SetActive();
|
sl@0
|
2015 |
}
|
sl@0
|
2016 |
}
|
sl@0
|
2017 |
#ifdef _DP_DEBUG
|
sl@0
|
2018 |
else
|
sl@0
|
2019 |
RDebug::Print(_L("Datapath is no longer active, not going to new state (this 0x%x)\n"),this);
|
sl@0
|
2020 |
#endif
|
sl@0
|
2021 |
}
|
sl@0
|
2022 |
|
sl@0
|
2023 |
/**
|
sl@0
|
2024 |
Runs the clip depending on the current data path and transfer state.
|
sl@0
|
2025 |
|
sl@0
|
2026 |
For example, fills the sink buffer if TDataPathState is EPlaying and TTransferState is ENeedSinkData.
|
sl@0
|
2027 |
*/
|
sl@0
|
2028 |
EXPORT_C void CMMFDataPath::RunL()
|
sl@0
|
2029 |
{
|
sl@0
|
2030 |
#ifdef _DP_DEBUG
|
sl@0
|
2031 |
RDebug::Print(_L("DP::RunL tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
2032 |
#endif
|
sl@0
|
2033 |
|
sl@0
|
2034 |
switch (iState)
|
sl@0
|
2035 |
{
|
sl@0
|
2036 |
case EStopped:
|
sl@0
|
2037 |
break;
|
sl@0
|
2038 |
case EPrimed:
|
sl@0
|
2039 |
//paused with stored position
|
sl@0
|
2040 |
break;
|
sl@0
|
2041 |
case EPlaying:
|
sl@0
|
2042 |
case ERecording:
|
sl@0
|
2043 |
case EConverting:
|
sl@0
|
2044 |
switch (iTransferState)
|
sl@0
|
2045 |
{
|
sl@0
|
2046 |
case EWaitSink:
|
sl@0
|
2047 |
case EWaitSource:
|
sl@0
|
2048 |
break;
|
sl@0
|
2049 |
case EInitializeSink:
|
sl@0
|
2050 |
InitializeSinkL();
|
sl@0
|
2051 |
break;
|
sl@0
|
2052 |
case EInitializeSource:
|
sl@0
|
2053 |
InitializeSourceL();
|
sl@0
|
2054 |
break;
|
sl@0
|
2055 |
case ENeedSourceData:
|
sl@0
|
2056 |
FillSourceBufferL();
|
sl@0
|
2057 |
break;
|
sl@0
|
2058 |
case ENeedSinkData:
|
sl@0
|
2059 |
FillSinkBufferL();
|
sl@0
|
2060 |
break;
|
sl@0
|
2061 |
case ENeedToMatchSourceToSink:
|
sl@0
|
2062 |
FillSinkBufferL();
|
sl@0
|
2063 |
break;
|
sl@0
|
2064 |
case ESendDataToSink:
|
sl@0
|
2065 |
EmptySinkBufferL();
|
sl@0
|
2066 |
break;
|
sl@0
|
2067 |
case EEndOfData:
|
sl@0
|
2068 |
EndOfData();
|
sl@0
|
2069 |
break;
|
sl@0
|
2070 |
}
|
sl@0
|
2071 |
break;
|
sl@0
|
2072 |
default:
|
sl@0
|
2073 |
break;
|
sl@0
|
2074 |
}
|
sl@0
|
2075 |
#ifdef _DP_DEBUG
|
sl@0
|
2076 |
RDebug::Print(_L("DP::RunL DONE\n"));
|
sl@0
|
2077 |
#endif
|
sl@0
|
2078 |
}
|
sl@0
|
2079 |
|
sl@0
|
2080 |
/**
|
sl@0
|
2081 |
Cancels the clip.
|
sl@0
|
2082 |
|
sl@0
|
2083 |
The default implementation is empty.
|
sl@0
|
2084 |
*/
|
sl@0
|
2085 |
EXPORT_C void CMMFDataPath::DoCancel()
|
sl@0
|
2086 |
{
|
sl@0
|
2087 |
//don't need to do anything as we don't have any async requests to other objects
|
sl@0
|
2088 |
}
|
sl@0
|
2089 |
|
sl@0
|
2090 |
/**
|
sl@0
|
2091 |
Handles errors coming from attached sources and passes them to the clients.
|
sl@0
|
2092 |
|
sl@0
|
2093 |
@param aError
|
sl@0
|
2094 |
Standard error code (KErrNone = No Error).
|
sl@0
|
2095 |
|
sl@0
|
2096 |
@return The event code returned to the data path. KErrNone if end of file is encountered.
|
sl@0
|
2097 |
*/
|
sl@0
|
2098 |
EXPORT_C TInt CMMFDataPath::RunError(TInt aError)
|
sl@0
|
2099 |
{
|
sl@0
|
2100 |
return DoSendEventToClient(KMMFErrorCategoryDataPathGeneralError, aError);
|
sl@0
|
2101 |
}
|
sl@0
|
2102 |
|
sl@0
|
2103 |
|
sl@0
|
2104 |
/**
|
sl@0
|
2105 |
Returns the duration of the clip.
|
sl@0
|
2106 |
|
sl@0
|
2107 |
@return The length of clip in TTimeIntervalMicroSeconds.
|
sl@0
|
2108 |
*/
|
sl@0
|
2109 |
TTimeIntervalMicroSeconds CMMFDataPath::Duration() const
|
sl@0
|
2110 |
{
|
sl@0
|
2111 |
TTimeIntervalMicroSeconds duration(0);
|
sl@0
|
2112 |
|
sl@0
|
2113 |
if ( iDataSource && ( iDataSource->DataSourceType() == KUidMmfFormatDecode ) )
|
sl@0
|
2114 |
{
|
sl@0
|
2115 |
//this updated version of datapath caches the duration of the
|
sl@0
|
2116 |
//source clip for efficiency - since this meathod is const
|
sl@0
|
2117 |
//we need to cast away the constness to set iCachedSourceDuration
|
sl@0
|
2118 |
CMMFDataPath* thisNonConst = const_cast<CMMFDataPath*>(this);
|
sl@0
|
2119 |
duration = STATIC_CAST(CMMFFormatDecode*, thisNonConst->iDataSource )->Duration( iMediaId ) ;
|
sl@0
|
2120 |
thisNonConst->iCachedSourceDuration = duration;
|
sl@0
|
2121 |
}
|
sl@0
|
2122 |
else if ( iDataSink && ( iDataSink->DataSinkType() == KUidMmfFormatEncode ) )
|
sl@0
|
2123 |
duration = STATIC_CAST(CMMFFormatEncode*, iDataSink )->Duration( iMediaId ) ;
|
sl@0
|
2124 |
|
sl@0
|
2125 |
return duration ;
|
sl@0
|
2126 |
}
|
sl@0
|
2127 |
|
sl@0
|
2128 |
/**
|
sl@0
|
2129 |
This is a virtual function datapath (or derivations off) that can be implemented but may be left blank for default behaviour.
|
sl@0
|
2130 |
|
sl@0
|
2131 |
Additional Stop() method specific to this datapath.
|
sl@0
|
2132 |
*/
|
sl@0
|
2133 |
void CMMFDataPath::DoStopL()
|
sl@0
|
2134 |
{
|
sl@0
|
2135 |
// Note that the datapath needs to be paused first
|
sl@0
|
2136 |
// before it can be stopped - this is important for audio play
|
sl@0
|
2137 |
// for instance to effect an immediate stop rather than playing out
|
sl@0
|
2138 |
// the current buffer.
|
sl@0
|
2139 |
|
sl@0
|
2140 |
|
sl@0
|
2141 |
|
sl@0
|
2142 |
// Stop data source and sink
|
sl@0
|
2143 |
iDataSource->SourceStopL(); // propagate state change to source
|
sl@0
|
2144 |
iDataSink->SinkStopL(); // propagate change down to sink
|
sl@0
|
2145 |
|
sl@0
|
2146 |
iSinkBufferWithSink = EFalse;
|
sl@0
|
2147 |
iSourceBufferWithSource = EFalse;
|
sl@0
|
2148 |
|
sl@0
|
2149 |
//Contains the completion code if the datapath completes as a result of an error
|
sl@0
|
2150 |
iDataPathCompletedErrorCode = KErrNone;
|
sl@0
|
2151 |
|
sl@0
|
2152 |
ResetRefBuffers(); // buffer references may not be valid any more
|
sl@0
|
2153 |
|
sl@0
|
2154 |
SetPositionL(iPlayWindowStartPosition); // reset position
|
sl@0
|
2155 |
|
sl@0
|
2156 |
iState = EStopped; // stop succeeded, set state to stopped
|
sl@0
|
2157 |
}
|
sl@0
|
2158 |
|
sl@0
|
2159 |
/**
|
sl@0
|
2160 |
This is a virtual function datapath (or derivations off) that can be implemented but may be left blank for default behaviour.
|
sl@0
|
2161 |
|
sl@0
|
2162 |
Additional Pause method specific to this datapath.
|
sl@0
|
2163 |
|
sl@0
|
2164 |
The DataPath implements pause by recording the current position and stopping the source and sink.
|
sl@0
|
2165 |
When Play is called the DataPath uses the stored position as the starting point and resumes
|
sl@0
|
2166 |
playing. The reason for this (rather than using the PauseL() API on sources and sinks) is that
|
sl@0
|
2167 |
some implementations do not support a suitable pause, therefore the DataPath is implemented to
|
sl@0
|
2168 |
support the lowest common denominator.
|
sl@0
|
2169 |
|
sl@0
|
2170 |
Note:
|
sl@0
|
2171 |
A suitable pause implementation will retain any buffers in use. There will be no
|
sl@0
|
2172 |
need to call PrimeL() prior to PlayL().
|
sl@0
|
2173 |
*/
|
sl@0
|
2174 |
void CMMFDataPath::DoPauseL()
|
sl@0
|
2175 |
{
|
sl@0
|
2176 |
#ifdef _DP_DEBUG
|
sl@0
|
2177 |
RDebug::Print(_L("DP::DoPauseL tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
2178 |
#endif
|
sl@0
|
2179 |
|
sl@0
|
2180 |
|
sl@0
|
2181 |
if ((iDataPathCreated) && ((iState == EPlaying) || (iState == EConverting)))
|
sl@0
|
2182 |
{
|
sl@0
|
2183 |
// try to pause source and sink
|
sl@0
|
2184 |
iDataSource->SourcePauseL(); // propagate state change to source
|
sl@0
|
2185 |
SetPositionL(Position());
|
sl@0
|
2186 |
iDataSink->SinkStopL();
|
sl@0
|
2187 |
|
sl@0
|
2188 |
iPauseCalled = ETrue; // indicate pause is called
|
sl@0
|
2189 |
|
sl@0
|
2190 |
iState = EPrimed; // go back to primed state (we're not playing)
|
sl@0
|
2191 |
|
sl@0
|
2192 |
iSinkBufferWithSink = EFalse;
|
sl@0
|
2193 |
iSourceBufferWithSource = EFalse;
|
sl@0
|
2194 |
|
sl@0
|
2195 |
ResetRefBuffers(); // buffer references may not be valid any more
|
sl@0
|
2196 |
|
sl@0
|
2197 |
Cancel(); //Stop the state machine
|
sl@0
|
2198 |
}
|
sl@0
|
2199 |
else if(iState == ERecording)
|
sl@0
|
2200 |
{
|
sl@0
|
2201 |
iPauseCalled = ETrue;
|
sl@0
|
2202 |
#ifdef _DP_DEBUG
|
sl@0
|
2203 |
RDebug::Print(_L("DP::DoPauseL Recording, pause datasource\n"));
|
sl@0
|
2204 |
#endif
|
sl@0
|
2205 |
iDataSource->SourcePauseL();
|
sl@0
|
2206 |
}
|
sl@0
|
2207 |
#ifdef _DP_DEBUG
|
sl@0
|
2208 |
RDebug::Print(_L("DP::DoPauseL - Done iReferenceAudioSamplesPlayed = %d\n"),iReferenceAudioSamplesPlayed);
|
sl@0
|
2209 |
RDebug::Print(_L("DP::DoPauseL - Done restart at %d tick-%d (this 0x%x)\n"),I64INT(iStartPosition.Int64()), User::TickCount(),this);
|
sl@0
|
2210 |
#endif
|
sl@0
|
2211 |
}
|
sl@0
|
2212 |
|
sl@0
|
2213 |
/**
|
sl@0
|
2214 |
This is a virtual function datapath (or derivations off) that can be implemented or may be left blank for default behaviour.
|
sl@0
|
2215 |
|
sl@0
|
2216 |
Additional Pause method specific to this datapath.
|
sl@0
|
2217 |
*/
|
sl@0
|
2218 |
void CMMFDataPath::DoEndOfDataL()
|
sl@0
|
2219 |
{
|
sl@0
|
2220 |
#ifdef _DP_DEBUG
|
sl@0
|
2221 |
RDebug::Print(_L("DP::DoEndOfDataL tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
2222 |
#endif
|
sl@0
|
2223 |
SetPositionL(iPlayWindowStartPosition); // reset position
|
sl@0
|
2224 |
|
sl@0
|
2225 |
ASSERT(iCompleteCallback);
|
sl@0
|
2226 |
iCompleteCallback->SignalDataPathComplete(iDataPathCompletedErrorCode);
|
sl@0
|
2227 |
|
sl@0
|
2228 |
ResetRefBuffers();
|
sl@0
|
2229 |
iState = EStopped;
|
sl@0
|
2230 |
|
sl@0
|
2231 |
#ifdef _DP_DEBUG
|
sl@0
|
2232 |
RDebug::Print(_L("DP::DoEndOfDataL - Done tick-%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
2233 |
#endif
|
sl@0
|
2234 |
}
|
sl@0
|
2235 |
|
sl@0
|
2236 |
|
sl@0
|
2237 |
/**
|
sl@0
|
2238 |
Passes error handling and general messages up to clients.
|
sl@0
|
2239 |
|
sl@0
|
2240 |
@param aEventType
|
sl@0
|
2241 |
Category code for the event. Category codes can be used as unique identifers.
|
sl@0
|
2242 |
@param aErrorCode
|
sl@0
|
2243 |
Standard error code.
|
sl@0
|
2244 |
|
sl@0
|
2245 |
@return The event code sent to client.
|
sl@0
|
2246 |
*/
|
sl@0
|
2247 |
//error handling
|
sl@0
|
2248 |
EXPORT_C TInt CMMFDataPath::DoSendEventToClient(TUid aEventType, TInt aErrorCode)
|
sl@0
|
2249 |
{
|
sl@0
|
2250 |
TMMFEvent event(aEventType, aErrorCode);
|
sl@0
|
2251 |
return iEventHandler.SendEventToClient(event);
|
sl@0
|
2252 |
}
|
sl@0
|
2253 |
|
sl@0
|
2254 |
/**
|
sl@0
|
2255 |
Passes error handling and general messages to clients.
|
sl@0
|
2256 |
|
sl@0
|
2257 |
@param aEvent
|
sl@0
|
2258 |
TMMFEvent supplied by callee (typically DoSendEventToClient)
|
sl@0
|
2259 |
|
sl@0
|
2260 |
@return The Event Message sent to the datapath event handler
|
sl@0
|
2261 |
*/
|
sl@0
|
2262 |
EXPORT_C TInt CMMFDataPath::SendEventToClient(const TMMFEvent& aEvent)
|
sl@0
|
2263 |
{
|
sl@0
|
2264 |
#ifdef _DP_DEBUG
|
sl@0
|
2265 |
RDebug::Print(_L("CMMFDataPath::SendEventToClient CODE = %d ticks=%d (this 0x%x)\n"),aEvent.iErrorCode,User::TickCount(),this);
|
sl@0
|
2266 |
RDebug::Print(_L("CMMFDataPath::SendEventToClient iEventType = %d == %d\n"),aEvent.iEventType, KMMFEventCategoryPlaybackComplete);
|
sl@0
|
2267 |
#endif
|
sl@0
|
2268 |
|
sl@0
|
2269 |
//If we have sent all the data to the sink, it is legal for it to send KErrUnderFlow
|
sl@0
|
2270 |
//to us and we can go through a clean shutdown, otherwise we pass the error to the
|
sl@0
|
2271 |
//controller and it is responsible for determining what to do
|
sl@0
|
2272 |
if(iAllDataSentToSink &&
|
sl@0
|
2273 |
(aEvent.iEventType == KMMFEventCategoryPlaybackComplete) &&
|
sl@0
|
2274 |
(aEvent.iErrorCode == KErrUnderflow))
|
sl@0
|
2275 |
{
|
sl@0
|
2276 |
#ifdef _DP_DEBUG
|
sl@0
|
2277 |
RDebug::Print(_L("CMMFDataPath::SendEventToClient Clean complete\n"));
|
sl@0
|
2278 |
#endif
|
sl@0
|
2279 |
//sink may not return the final buffer once it has finished with it
|
sl@0
|
2280 |
//force ourselves into the EndOfData state
|
sl@0
|
2281 |
if(iTransferState != EEndOfData)
|
sl@0
|
2282 |
{
|
sl@0
|
2283 |
iDataPathCompletedErrorCode = KErrNone;
|
sl@0
|
2284 |
TRAP_IGNORE(DoEndOfDataL());
|
sl@0
|
2285 |
}
|
sl@0
|
2286 |
|
sl@0
|
2287 |
iCompleteCallback->SignalSinkComplete(KErrNone);
|
sl@0
|
2288 |
return KErrNone;
|
sl@0
|
2289 |
}
|
sl@0
|
2290 |
|
sl@0
|
2291 |
|
sl@0
|
2292 |
|
sl@0
|
2293 |
return iEventHandler.SendEventToClient(aEvent);
|
sl@0
|
2294 |
}
|
sl@0
|
2295 |
|
sl@0
|
2296 |
CMMFDataPath::CCompleteCallback::CCompleteCallback(CMMFDataPath& aDataPath, TBool aWaitForSink)
|
sl@0
|
2297 |
: CActive(EPriorityStandard),
|
sl@0
|
2298 |
iDataPath(aDataPath),
|
sl@0
|
2299 |
iWaitForSink(aWaitForSink)
|
sl@0
|
2300 |
{
|
sl@0
|
2301 |
CActiveScheduler::Add(this);
|
sl@0
|
2302 |
}
|
sl@0
|
2303 |
|
sl@0
|
2304 |
CMMFDataPath::CCompleteCallback::~CCompleteCallback()
|
sl@0
|
2305 |
{
|
sl@0
|
2306 |
Cancel();
|
sl@0
|
2307 |
}
|
sl@0
|
2308 |
|
sl@0
|
2309 |
void CMMFDataPath::CCompleteCallback::SignalDataPathComplete(TInt aDataPathError)
|
sl@0
|
2310 |
{
|
sl@0
|
2311 |
iDataPathComplete = ETrue;
|
sl@0
|
2312 |
iDataPathError = aDataPathError;
|
sl@0
|
2313 |
if (!IsActive())
|
sl@0
|
2314 |
{
|
sl@0
|
2315 |
// Signal ourselves to run with the given completion code
|
sl@0
|
2316 |
TRequestStatus* status = &ActiveStatus();
|
sl@0
|
2317 |
User::RequestComplete(status, KErrNone);
|
sl@0
|
2318 |
}
|
sl@0
|
2319 |
}
|
sl@0
|
2320 |
|
sl@0
|
2321 |
void CMMFDataPath::CCompleteCallback::SignalSinkComplete(TInt aSinkError)
|
sl@0
|
2322 |
{
|
sl@0
|
2323 |
iSinkComplete = ETrue;
|
sl@0
|
2324 |
iSinkError = aSinkError;
|
sl@0
|
2325 |
if (!IsActive())
|
sl@0
|
2326 |
{
|
sl@0
|
2327 |
// Signal ourselves to run with the given completion code
|
sl@0
|
2328 |
TRequestStatus* status = &ActiveStatus();
|
sl@0
|
2329 |
User::RequestComplete(status, KErrNone);
|
sl@0
|
2330 |
}
|
sl@0
|
2331 |
}
|
sl@0
|
2332 |
|
sl@0
|
2333 |
|
sl@0
|
2334 |
TRequestStatus& CMMFDataPath::CCompleteCallback::ActiveStatus()
|
sl@0
|
2335 |
{
|
sl@0
|
2336 |
SetActive();
|
sl@0
|
2337 |
return iStatus;
|
sl@0
|
2338 |
}
|
sl@0
|
2339 |
|
sl@0
|
2340 |
void CMMFDataPath::CCompleteCallback::DoCancel()
|
sl@0
|
2341 |
{
|
sl@0
|
2342 |
}
|
sl@0
|
2343 |
|
sl@0
|
2344 |
void CMMFDataPath::CCompleteCallback::RunL()
|
sl@0
|
2345 |
{
|
sl@0
|
2346 |
if (iWaitForSink)
|
sl@0
|
2347 |
{
|
sl@0
|
2348 |
if (iDataPathComplete && iSinkComplete)
|
sl@0
|
2349 |
{
|
sl@0
|
2350 |
#ifdef _DP_DEBUG
|
sl@0
|
2351 |
RDebug::Print(_L("CMMFDataPath::CCompleteCallback::RunL STOPPING src & sink ticks=%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
2352 |
#endif
|
sl@0
|
2353 |
|
sl@0
|
2354 |
TRAP_IGNORE(iDataPath.DoStopL())
|
sl@0
|
2355 |
|
sl@0
|
2356 |
iDataPathComplete = EFalse;
|
sl@0
|
2357 |
iSinkComplete = EFalse;
|
sl@0
|
2358 |
|
sl@0
|
2359 |
// if we have to wait for the sink to complete, always use the sink error
|
sl@0
|
2360 |
iDataPath.DoSendEventToClient(KMMFEventCategoryPlaybackComplete, iSinkError);
|
sl@0
|
2361 |
}
|
sl@0
|
2362 |
}
|
sl@0
|
2363 |
else if (iDataPathComplete)
|
sl@0
|
2364 |
{
|
sl@0
|
2365 |
#ifdef _DP_DEBUG
|
sl@0
|
2366 |
RDebug::Print(_L("CMMFDataPath::CCompleteCallback::RunL STOPPING src & sink ticks=%d (this 0x%x)\n"),User::TickCount(),this);
|
sl@0
|
2367 |
#endif
|
sl@0
|
2368 |
|
sl@0
|
2369 |
TRAP_IGNORE(iDataPath.DoStopL())
|
sl@0
|
2370 |
|
sl@0
|
2371 |
iDataPathComplete = EFalse;
|
sl@0
|
2372 |
iSinkComplete = EFalse;
|
sl@0
|
2373 |
|
sl@0
|
2374 |
iDataPath.DoSendEventToClient(KMMFEventCategoryPlaybackComplete, iDataPathError);
|
sl@0
|
2375 |
}
|
sl@0
|
2376 |
}
|
sl@0
|
2377 |
|
sl@0
|
2378 |
EXPORT_C TInt CMMFDataPath::SetBlockLength(TUint aBlockLength)
|
sl@0
|
2379 |
{
|
sl@0
|
2380 |
MMMFDevSoundCustomInterfaceFileBlockLength* fileBlockLengthCI = NULL;
|
sl@0
|
2381 |
TInt err = KErrNotSupported;
|
sl@0
|
2382 |
if (iCodec)
|
sl@0
|
2383 |
{
|
sl@0
|
2384 |
err = iCodec->ExtensionInterface(KUidCustomInterfaceDevSoundFileBlockLength.iUid, (TAny*&)fileBlockLengthCI);
|
sl@0
|
2385 |
}
|
sl@0
|
2386 |
|
sl@0
|
2387 |
if (err == KErrNone)
|
sl@0
|
2388 |
{
|
sl@0
|
2389 |
fileBlockLengthCI->SetFileBlockLength(aBlockLength);
|
sl@0
|
2390 |
}
|
sl@0
|
2391 |
|
sl@0
|
2392 |
return err;
|
sl@0
|
2393 |
}
|
sl@0
|
2394 |
|