|
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <mmf/server/mmfswcodecwrapper.h> |
|
17 #include "mmfSwCodecPlayDataPath.h" |
|
18 #include "mmfSwCodecRecordDataPath.h" |
|
19 #include "mmfSwCodecConvertDataPath.h" |
|
20 #include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh> |
|
21 #include "mmfswcodecwrapperCustomInterfaces.h" |
|
22 #include <mmf/common/mmfpaniccodes.h> |
|
23 |
|
24 |
|
25 |
|
26 /** |
|
27 * Internal panic |
|
28 * @internalComponent |
|
29 */ |
|
30 void Panic(TInt aPanicCode) |
|
31 { |
|
32 _LIT(KMMFSwCodecWrapperPanicCategory, "MMFSwCodecWrapper"); |
|
33 User::Panic(KMMFSwCodecWrapperPanicCategory, aPanicCode); |
|
34 } |
|
35 |
|
36 |
|
37 /** |
|
38 * This method is not be exported as it is only |
|
39 * intended to be called within this DLL. |
|
40 * It's purpose is to assign an RMdaDevSound to the play |
|
41 * custom interface |
|
42 * @internalComponent |
|
43 */ |
|
44 void TPlayCustomInterface::SetDevice(RMdaDevSound* aDevice) |
|
45 { |
|
46 iDevice = aDevice; |
|
47 } |
|
48 |
|
49 void TPlayCustomInterface::SetVolume(TUint aVolume) |
|
50 { |
|
51 iVolume = aVolume; |
|
52 if (iDevice && iDevice->Handle()) |
|
53 iDevice->SetPlayVolume(iVolume); |
|
54 } |
|
55 |
|
56 /** |
|
57 * Procedure to get the number of bytes played by the device driver |
|
58 * If there is no handle available to the device driver then the |
|
59 * procedure returns the last known value |
|
60 * @released |
|
61 * @return number of bytes played |
|
62 */ |
|
63 TUint TPlayCustomInterface::BytesPlayed() |
|
64 { |
|
65 if(iDevice) |
|
66 { |
|
67 if (iDevice->Handle()) |
|
68 iBytesPlayed = iDevice->BytesPlayed(); |
|
69 } |
|
70 return iBytesPlayed; |
|
71 } |
|
72 |
|
73 /** |
|
74 * Procedure to get the number of bytes recorded by the device |
|
75 * @released |
|
76 * @return The number of bytes recorded by an existing datapath. If there |
|
77 * is no datapath, then the last known number of bytes recorded will be returned. |
|
78 */ |
|
79 TUint TRecordCustomInterface::BytesRecorded() |
|
80 { |
|
81 if(iDataPath) |
|
82 { |
|
83 iBytesRecorded = iDataPath->RecordedBytesCount(); |
|
84 } |
|
85 return iBytesRecorded; |
|
86 } |
|
87 |
|
88 /** |
|
89 Constructor. |
|
90 */ |
|
91 EXPORT_C CMMFSwCodecWrapper::CMMFSwCodecWrapper() |
|
92 { |
|
93 } |
|
94 |
|
95 /** |
|
96 Destructor. |
|
97 |
|
98 The destructor is called by ECom framework allowing derived classes |
|
99 to clean up implementation specific resources. The sound |
|
100 device drivers are freed. |
|
101 */ |
|
102 EXPORT_C CMMFSwCodecWrapper::~CMMFSwCodecWrapper() |
|
103 { |
|
104 delete iDataPath; |
|
105 delete iCodec; |
|
106 delete iPlayCustomInterface; |
|
107 delete iRecordCustomInterface; |
|
108 } |
|
109 |
|
110 /** |
|
111 Initializes the hardware device tasks - in the case of a |
|
112 sw codec wrapper 'hardware device' this consits of loading the |
|
113 sound device drivers and creating the CMMFSwCodec. |
|
114 |
|
115 @param aDevInfo |
|
116 Device initialization parameters. |
|
117 Only the iHwDeviceObserver is used for CMFSwCodecWrapper |
|
118 derived CMMFHwDevices. |
|
119 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
120 another of the system-wide error codes. |
|
121 */ |
|
122 EXPORT_C TInt CMMFSwCodecWrapper::Init(THwDeviceInitParams &aDevInfo) |
|
123 { |
|
124 |
|
125 // [ precondition that aDevInfo has a valid observer ] |
|
126 if (!aDevInfo.iHwDeviceObserver) |
|
127 return KErrArgument; |
|
128 |
|
129 iHwDeviceObserver = aDevInfo.iHwDeviceObserver; |
|
130 #ifndef SYMBIAN_MDF_SHAREDCHUNK_SOUNDDRIVER //Adapter loads the drivers |
|
131 // Try to load the audio physical driver |
|
132 TInt ret = User::LoadPhysicalDevice(KPddFileName); |
|
133 if ((ret!=KErrNone) && (ret!=KErrAlreadyExists)) |
|
134 return ret; |
|
135 |
|
136 // Try to load the audio logical driver |
|
137 ret = User::LoadLogicalDevice(KLddFileName); |
|
138 if ((ret!=KErrNone) && (ret!=KErrAlreadyExists)) |
|
139 return ret; |
|
140 #endif |
|
141 iCodec = &(Codec()); //create codec |
|
142 |
|
143 //[ assert the post condition ] |
|
144 if (!iCodec) |
|
145 return KErrNotSupported; |
|
146 |
|
147 return KErrNone; |
|
148 } |
|
149 |
|
150 |
|
151 /** |
|
152 Starts Encoding or Decoding task(s) based on the parameter specified. |
|
153 |
|
154 @param aFuncCmd |
|
155 The device function specifying the requested service i.e. decode or encode |
|
156 where EDevEncode = Record, EDevDecode = Play and EDevNullFunc = Convert. |
|
157 @param aFlowCmd |
|
158 The device flow directions for requested service. |
|
159 This parameter is ignored for CMMFSwCodecWrapper CMMFHwDevicePlugins |
|
160 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
161 another of the system-wide error codes. |
|
162 */ |
|
163 EXPORT_C TInt CMMFSwCodecWrapper::Start(TDeviceFunc aFuncCmd, TDeviceFlow /*aFlowCmd*/) |
|
164 { |
|
165 TInt error = KErrNone; |
|
166 |
|
167 // [ precondition that aFuncCmd is valid] |
|
168 if (!((aFuncCmd == EDevEncode)|(aFuncCmd == EDevDecode)|(aFuncCmd == EDevNullFunc))) |
|
169 return KErrArgument; |
|
170 |
|
171 // [ precondition that iCodec is present] |
|
172 if (!iCodec) |
|
173 return KErrNotReady; //make sure the codec has been added |
|
174 |
|
175 switch (aFuncCmd) |
|
176 { |
|
177 case EDevEncode: // Audio record |
|
178 { |
|
179 error = StartEncode(); |
|
180 } |
|
181 break; |
|
182 case EDevDecode: // Audio play |
|
183 { |
|
184 error = StartDecode(); |
|
185 } |
|
186 break; |
|
187 case EDevNullFunc: //Audio Convert |
|
188 { |
|
189 error = StartConvert(); |
|
190 } |
|
191 break; |
|
192 default: |
|
193 error = KErrNotSupported; |
|
194 break; |
|
195 } |
|
196 |
|
197 //[ assert the post conditions ] |
|
198 #ifdef DEBUG |
|
199 if (!error) |
|
200 {//only assert if no error otherwise post consitions not valid |
|
201 __ASSERT_DEBUG(iDataPath, Panic(EMMFSwCodecWrapperNoDataPath)); |
|
202 if ((aFuncCmd == EDevEncode)||(aFuncCmd == EDevDecode)) |
|
203 __ASSERT_DEBUG(iDataPath->Device().Handle(), Panic(EMMFSwCodecWrapperNoDevice)); |
|
204 } |
|
205 #endif |
|
206 if(error != KErrNone && iDataPath && aFuncCmd!=EDevEncode) |
|
207 {//if error happens after opening LDD close it |
|
208 if (iDataPath->Device().Handle()!= KNullHandle) |
|
209 { |
|
210 iDataPath->Device().Close(); |
|
211 } |
|
212 } |
|
213 |
|
214 return error; |
|
215 } |
|
216 |
|
217 |
|
218 TInt CMMFSwCodecWrapper::StartDecode() |
|
219 { |
|
220 TInt error = KErrNone; |
|
221 |
|
222 //[ assert precondition that play custom interface is present] |
|
223 //if there is no play custom interface then the user of the CMMFSwCodecWrapper |
|
224 //cannot have set any of the custom settings such as sample rate. |
|
225 if (!iPlayCustomInterface) |
|
226 return KErrNotReady; |
|
227 |
|
228 //play |
|
229 if (!iDataPath) |
|
230 {//create a datapath |
|
231 TRAP(error,iDataPath = CMMFSwCodecPlayDataPath::NewL()); |
|
232 //if datapath could not be created, return error code |
|
233 if (error != KErrNone) |
|
234 { |
|
235 return error; |
|
236 } |
|
237 |
|
238 //here we are sure iDataPath has been correctly allocated |
|
239 iDataPath->SetObserver(*iHwDeviceObserver); |
|
240 error = iDataPath->AddCodec(*iCodec); |
|
241 if (error == KErrNone) |
|
242 { |
|
243 iDeviceBufferSize = (iCodec->SinkBufferSize()); |
|
244 static_cast<CMMFSwCodecPlayDataPath*>(iDataPath)->SetPlayCustomInterface(*iPlayCustomInterface); |
|
245 } |
|
246 else |
|
247 { |
|
248 // if could not add codec to datapath, return error code |
|
249 return error; |
|
250 } |
|
251 } |
|
252 |
|
253 //Here we know that error is KerrNone, now we can check the state of the datapath |
|
254 if (iDataPath->State() != CMMFSwCodecDataPath::EPlaying) |
|
255 {//datapath was created ok and we are not playing |
|
256 if (iDataPath->State() == CMMFSwCodecDataPath::EStopped) |
|
257 {//starting from 'fresh so set sound device settings |
|
258 if (!iDataPath->Device().Handle()) |
|
259 {//if Device() is called then we need a valid sound device handle |
|
260 error = iDataPath->Device().Open(); |
|
261 if (error != KErrNone) |
|
262 return error; |
|
263 } |
|
264 static_cast<TPlayCustomInterface*>(iPlayCustomInterface)->SetDevice(&(iDataPath->Device())); |
|
265 iDataPath->Device().SetPlayVolume(iPlayCustomInterface->Volume()); |
|
266 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; |
|
267 soundDeviceSettings().iRate = iSampleRate; |
|
268 //this would normally be pcm16 |
|
269 soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; |
|
270 //1 = mono 2 = stereo |
|
271 soundDeviceSettings().iChannels = iChannels; |
|
272 //tell sound driver what buffer size to expect |
|
273 //it is up the the implementor to make use the device can support |
|
274 //the required buffer size |
|
275 soundDeviceSettings().iBufferSize = iDeviceBufferSize; |
|
276 error = iDataPath->Device().SetPlayFormat(soundDeviceSettings); |
|
277 }//iDataPath->State() == CMMFSwCodecDataPath::EStopped |
|
278 //else resuming from pause |
|
279 if ((error == KErrNone)||(error == KErrInUse)) |
|
280 error = iDataPath->Start(); |
|
281 }//status == KErrNone |
|
282 return error; |
|
283 } |
|
284 |
|
285 |
|
286 TInt CMMFSwCodecWrapper::StartEncode() |
|
287 {//record |
|
288 |
|
289 //[ assert precondition that record custom interface is present] |
|
290 //if there is no record custom interface then the user of the CMMFSwCodecWrapper |
|
291 //cannot have set any of the custom settings such as sample rate. |
|
292 if (!iRecordCustomInterface) |
|
293 return KErrNotReady; |
|
294 |
|
295 TInt error = KErrNone; |
|
296 if (!iDataPath) |
|
297 { |
|
298 TRAP(error,iDataPath = CMMFSwCodecRecordDataPath::NewL()); |
|
299 //if datapath could not be created, return error code |
|
300 if (error != KErrNone) |
|
301 { |
|
302 return error; |
|
303 } |
|
304 |
|
305 //here we are sure iDataPath has been correctly allocated |
|
306 iDataPath->SetObserver(*iHwDeviceObserver); |
|
307 error = iDataPath->AddCodec(*iCodec); |
|
308 if (error == KErrNone) |
|
309 { |
|
310 iDeviceBufferSize = (iCodec->SourceBufferSize()); |
|
311 static_cast<TRecordCustomInterface*>(iRecordCustomInterface)->SetDataPath(static_cast<CMMFSwCodecRecordDataPath*>(iDataPath)); |
|
312 } |
|
313 else |
|
314 { |
|
315 // if could not add codec to datapath, return error code |
|
316 return error; |
|
317 } |
|
318 } |
|
319 |
|
320 //Here we know that error is KerrNone, now we can check the state of the datapath |
|
321 if (iDataPath->State() != CMMFSwCodecDataPath::EPlaying) |
|
322 { |
|
323 if (iDataPath->State() == CMMFSwCodecDataPath::EStopped) |
|
324 { |
|
325 MSwSetParamInterface* setParams = |
|
326 static_cast<MSwSetParamInterface*>(iDataPath->CustomInterface(KUidSwSetParamInterface)); |
|
327 ASSERT(!error); // should not get here if error set |
|
328 error = setParams->SetGain(iRecordCustomInterface->Gain()); |
|
329 if (!error) |
|
330 { |
|
331 error = setParams->SetNumChannels(iChannels); |
|
332 } |
|
333 if (!error) |
|
334 { |
|
335 error = setParams->SetSampleRate(iSampleRate); |
|
336 } |
|
337 } |
|
338 if (error == KErrNone) |
|
339 { |
|
340 error = iDataPath->Start(); |
|
341 } |
|
342 } |
|
343 return error; |
|
344 } |
|
345 |
|
346 |
|
347 TInt CMMFSwCodecWrapper::StartConvert() |
|
348 {//convert |
|
349 |
|
350 TInt error = KErrNone; |
|
351 if (!iDataPath) |
|
352 { |
|
353 TRAP(error,iDataPath = CMMFSwCodecConvertDataPath::NewL()); |
|
354 if (error != KErrNone) |
|
355 { |
|
356 return error; |
|
357 } |
|
358 } |
|
359 |
|
360 //Here we know we are not dereferencing a null pointer as iDataPath has been correctly initialised |
|
361 iDataPath->SetObserver(*iHwDeviceObserver); |
|
362 error = iDataPath->AddCodec(*iCodec); |
|
363 |
|
364 if (error == KErrNone) |
|
365 { |
|
366 error = iDataPath->Start(); |
|
367 } |
|
368 |
|
369 return error; |
|
370 } |
|
371 |
|
372 /** |
|
373 Temporarily suspends the current task of decoding or encoding. |
|
374 |
|
375 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
376 another of the system-wide error codes. |
|
377 */ |
|
378 EXPORT_C TInt CMMFSwCodecWrapper::Pause() |
|
379 { |
|
380 // [ precondition that datapath exists ] |
|
381 if (!iDataPath) |
|
382 return KErrNotReady; |
|
383 |
|
384 iDataPath->Pause(); |
|
385 return KErrNone; |
|
386 } |
|
387 |
|
388 /** |
|
389 Stops the current on-going task. |
|
390 |
|
391 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
392 another of the system-wide error codes. |
|
393 */ |
|
394 EXPORT_C TInt CMMFSwCodecWrapper::Stop() |
|
395 { |
|
396 // [ precondition that datapath exists ] |
|
397 if (!iDataPath) |
|
398 return KErrNotReady; |
|
399 |
|
400 iDataPath->Stop(); |
|
401 return KErrNone; |
|
402 } |
|
403 |
|
404 |
|
405 /** |
|
406 Stops and deletes the codec. |
|
407 |
|
408 This default implementation simply calls DeleteCodec() and then Stop() |
|
409 but real hardware devices might use this method to free up resources. |
|
410 |
|
411 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
412 another of the system-wide error codes. |
|
413 */ |
|
414 EXPORT_C TInt CMMFSwCodecWrapper::StopAndDeleteCodec() |
|
415 { |
|
416 TInt stopError = Stop(); |
|
417 TInt deleteError = DeleteCodec(); |
|
418 |
|
419 if (stopError != KErrNone) |
|
420 return stopError; |
|
421 else |
|
422 return deleteError; |
|
423 } |
|
424 |
|
425 /** |
|
426 Deletes the codec |
|
427 This default implementation does nothing |
|
428 but real hardware devices might use this method to free up resources. |
|
429 @return Error code. KErrNone if successful |
|
430 */ |
|
431 EXPORT_C TInt CMMFSwCodecWrapper::DeleteCodec() |
|
432 { |
|
433 return KErrNone; |
|
434 } |
|
435 |
|
436 /** |
|
437 Call this function to notify hardware device implementation that |
|
438 data is available in aFillBufferPtr for decoding. |
|
439 |
|
440 @param aFillBufferPtr |
|
441 The data buffer filled by the observer. |
|
442 |
|
443 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
444 another of the system-wide error codes. |
|
445 */ |
|
446 EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferFilled(CMMFBuffer& aFillBufferPtr) |
|
447 { |
|
448 TRAPD(err,iDataPath->BufferFilledL(STATIC_CAST(CMMFDataBuffer&, aFillBufferPtr))); |
|
449 return err; |
|
450 } |
|
451 |
|
452 /** |
|
453 Call this function to notify hardware device implementation that |
|
454 data in aEmptyBufferPtr from encoding is processed. |
|
455 |
|
456 @param aBuffer |
|
457 The data buffer processed by observer. |
|
458 |
|
459 @return An error code indicating if the function call was successful. KErrNone on success, otherwise |
|
460 another of the system-wide error codes. |
|
461 */ |
|
462 EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferEmptied(CMMFBuffer& aBuffer) |
|
463 { |
|
464 TRAPD(err,iDataPath->BufferEmptiedL(STATIC_CAST(CMMFDataBuffer&, aBuffer))); |
|
465 return err; |
|
466 } |
|
467 |
|
468 |
|
469 /** |
|
470 Retrieves a custom interface to the device. |
|
471 The reference CMMFSwCodecWrapper supports two standard custom interfaces, |
|
472 MPlayCustomInterface and MRecordCustomInterface. |
|
473 |
|
474 @param aInterface |
|
475 Interface UID, defined with the custom interface. |
|
476 aInterface = KMmfPlaySettingsCustomInterface for MPlayCustomInterface, |
|
477 aInterface = KMmfRecordSettingsCustomInterface for MRecordCustomInterface. |
|
478 aInterface = KMmfUidEmptyBuffersCustomInterface for MEmptyBuffersCustomInterface |
|
479 Actual device implementations of CMMFSwCodecWrapper may do this differently however. |
|
480 @return A pointer to the interface implementation, or NULL if the device can not |
|
481 implement the interface requested. The return value must be cast to the |
|
482 correct type by the user. |
|
483 */ |
|
484 EXPORT_C TAny* CMMFSwCodecWrapper::CustomInterface(TUid aInterface) |
|
485 { |
|
486 TAny* ret = NULL; |
|
487 TInt err = KErrNone; |
|
488 if (aInterface.iUid == KMmfPlaySettingsCustomInterface) |
|
489 { |
|
490 if (!iPlayCustomInterface) |
|
491 TRAP(err,iPlayCustomInterface = new(ELeave)TPlayCustomInterface()); |
|
492 if (err) |
|
493 ret = NULL; |
|
494 else |
|
495 ret = static_cast<TAny*>(iPlayCustomInterface); |
|
496 } |
|
497 else if (aInterface.iUid == KMmfRecordSettingsCustomInterface) |
|
498 { |
|
499 if (!iRecordCustomInterface) |
|
500 TRAP(err,iRecordCustomInterface = new(ELeave)TRecordCustomInterface()); |
|
501 if (err) |
|
502 ret = NULL; |
|
503 else |
|
504 ret = static_cast<TAny*>(iRecordCustomInterface); |
|
505 } |
|
506 |
|
507 else if (aInterface.iUid == KMmfUidEmptyBuffersCustomInterface || aInterface == KTimePlayedCustomInterfaceTypeUid || aInterface == KIgnoreUnderflowCustomInterfaceTypeUid) |
|
508 { |
|
509 if (!iDataPath) |
|
510 { |
|
511 ret = NULL; |
|
512 } |
|
513 else |
|
514 { |
|
515 ret = static_cast<CMMFSwCodecDataPath*>(iDataPath)->CustomInterface(aInterface); |
|
516 } |
|
517 } |
|
518 |
|
519 return ret; |
|
520 } |
|
521 |
|
522 |
|
523 /** |
|
524 Used to configure the sample rate and stereo mode of a CMMFHwDevice plugin. |
|
525 |
|
526 The configuration of HwDevices is device specific and is not used in any of the reference |
|
527 devices that return KErrNotSupported. |
|
528 |
|
529 @param aConfig |
|
530 The device configuration. |
|
531 */ |
|
532 EXPORT_C TInt CMMFSwCodecWrapper::SetConfig(TTaskConfig& aConfig) |
|
533 { |
|
534 if (aConfig.iUid != KUidRefDevSoundTaskConfig) |
|
535 return KErrArgument; |
|
536 iSampleRate = aConfig.iRate; |
|
537 |
|
538 if (aConfig.iStereoMode == ETaskMono) |
|
539 { |
|
540 iChannels = 1; |
|
541 } |
|
542 else if (aConfig.iStereoMode == ETaskInterleaved || aConfig.iStereoMode == ETaskNonInterleaved) |
|
543 { |
|
544 iChannels = 2; |
|
545 } |
|
546 else |
|
547 { |
|
548 return KErrArgument; |
|
549 } |
|
550 return KErrNone; |
|
551 } |
|
552 |
|
553 /** |
|
554 Used to set iVbrFlag on the datapath. |
|
555 |
|
556 This method is used to set the iVbrFlag in datapath. This flag is added to datapath to avail the |
|
557 alternative dataflow wherein datapath makes sure that destinationbuffer is filled to its maximum length |
|
558 before sending it to the sound driver. Sending the buffer directly to the device causes underflow incase of VBR codecs. |
|
559 */ |
|
560 EXPORT_C void CMMFSwCodecWrapper::SetVbrFlag() |
|
561 { |
|
562 if(iDataPath) |
|
563 { |
|
564 TUid cUid = TUid::Uid(KSetVbrFlagCustomInterfaceTypeUid); |
|
565 iDataPath->CustomInterface(cUid); |
|
566 } |
|
567 } |
|
568 |
|
569 |