|
1 // Copyright (c) 2001-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 <e32base.h> |
|
17 #ifdef SYMBIAN_MULTIMEDIA_CODEC_API |
|
18 #include <OMX_Core.h> |
|
19 #endif // SYMBIAN_MULTIMEDIA_CODEC_API |
|
20 #include "MmfDevSoundSessionBody.h" |
|
21 #include "MmfDevSoundSessionXtnd.h" |
|
22 #include "MmfDevSoundServer.h" |
|
23 #include <mdaaudiotoneplayer.h> |
|
24 #include <mmf/server/mmfdatabuffer.h> |
|
25 #include <mmffourcc.h> |
|
26 #include <mmfhwdeviceimplementationuids.hrh> |
|
27 #include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh> // KUidRefDevSoundTaskConfig & KMmfUidEmptyBuffersCustomInterface |
|
28 #include <mmf/server/mmfdevsoundcustominterfacesupport.h> |
|
29 |
|
30 const TUid KEmptyBuffersCustomInterfaceTypeUid = {KMmfUidEmptyBuffersCustomInterface}; |
|
31 |
|
32 /* |
|
33 * |
|
34 * Default Constructor. |
|
35 * |
|
36 * No default implementation. CMMFDevSoundProxy implements 2-phase construction. |
|
37 * |
|
38 */ |
|
39 CMMFDevSoundSvrImp::CMMFDevSoundSvrImp(CMMFDevSoundSessionXtnd* aParent) |
|
40 : iParent(*aParent) |
|
41 { |
|
42 iMode= EMMFDevSoundStateIdle; |
|
43 //Set reasonable default values for DTMF |
|
44 iDTMFGen.SetToneDurations(250000,50000,250000); |
|
45 } |
|
46 |
|
47 /* |
|
48 * |
|
49 * Destructor. |
|
50 * |
|
51 * Deletes all objects and releases all resource owned by this |
|
52 * instance. |
|
53 * |
|
54 */ |
|
55 CMMFDevSoundSvrImp::~CMMFDevSoundSvrImp() |
|
56 { |
|
57 delete iToneBuffer1; |
|
58 delete iToneBuffer2; |
|
59 delete iDevSoundEventHandler; |
|
60 if( iAudioPolicyProxy != NULL) |
|
61 { |
|
62 iAudioPolicyProxy->Close(); |
|
63 delete iAudioPolicyProxy; |
|
64 } |
|
65 delete iDevSoundUtil; |
|
66 delete iFixedSequences; |
|
67 delete iCMMFHwDevice; |
|
68 #ifdef SYMBIAN_MULTIMEDIA_CODEC_API |
|
69 OMX_Deinit(); |
|
70 #endif // SYMBIAN_MULTIMEDIA_CODEC_API |
|
71 } |
|
72 |
|
73 /* |
|
74 * |
|
75 * Constructs, and returns a pointer to, a new CMMFDevSoundSvrImp object. |
|
76 * |
|
77 * Leaves on failure. |
|
78 * |
|
79 */ |
|
80 CMMFDevSoundSvrImp* CMMFDevSoundSvrImp::NewL(CMMFDevSoundSessionXtnd* aParent) |
|
81 { |
|
82 CMMFDevSoundSvrImp* self = new (ELeave) CMMFDevSoundSvrImp(aParent); |
|
83 return self; |
|
84 } |
|
85 |
|
86 /* |
|
87 * |
|
88 * 3rd phase constructor - assumes that iParent has already been set up properly |
|
89 * (During ConstructL() it has yet to be |
|
90 * |
|
91 */ |
|
92 void CMMFDevSoundSvrImp::Construct3L(RServer2& aPolicyServerHandle) |
|
93 { |
|
94 // all these data properties should be NULL, but add ASSERTs to verity |
|
95 ASSERT(iAudioPolicyProxy==NULL); |
|
96 iAudioPolicyProxy = new (ELeave) RMMFAudioPolicyProxy(); |
|
97 ASSERT(iDevSoundEventHandler==NULL); |
|
98 iDevSoundEventHandler = CMMFDevSoundEventHandler::NewL(iAudioPolicyProxy); |
|
99 User::LeaveIfError(iAudioPolicyProxy->Open(aPolicyServerHandle)); |
|
100 iDevSoundEventHandler->SetDevSoundInfo(&iParent); |
|
101 |
|
102 iDevSoundUtil = CMMFDevSoundUtility::NewL(); |
|
103 // Initialize Fixed sequence related |
|
104 iDevSoundUtil->InitializeFixedSequenceL(&iFixedSequences); |
|
105 |
|
106 #ifdef SYMBIAN_MULTIMEDIA_CODEC_API |
|
107 OMX_Init(); |
|
108 #endif // SYMBIAN_MULTIMEDIA_CODEC_API |
|
109 PreInitializeL(); |
|
110 } |
|
111 |
|
112 /** |
|
113 * internal procedure to perform all initialization prior to setting the |
|
114 * data type 4CC code |
|
115 */ |
|
116 void CMMFDevSoundSvrImp::PreInitializeL() |
|
117 { |
|
118 // Set default values for priority settings: Note: Client must |
|
119 // over ride default settings by calling SetPrioirtySettings |
|
120 iAudioPolicyPrioritySettings.iState = EMMFStateStopped; |
|
121 iAudioPolicyPrioritySettings.iPref = EMdaPriorityPreferenceNone; |
|
122 iAudioPolicyPrioritySettings.iPriority = 0; |
|
123 |
|
124 // Get device capabilities and current settings from Audio Policy: |
|
125 User::LeaveIfError(iAudioPolicyProxy->GetPlayFormatsSupported(iPlayFormatsSupported)); |
|
126 User::LeaveIfError(iAudioPolicyProxy->GetPlayFormat(iPlayFormat)); |
|
127 User::LeaveIfError(iAudioPolicyProxy->GetRecordFormatsSupported(iRecordFormatsSupported)); |
|
128 User::LeaveIfError(iAudioPolicyProxy->GetRecordFormat(iRecordFormat)); |
|
129 |
|
130 //default to play until we know we are recording |
|
131 User::LeaveIfError(InitializeFormat(iPlayFormatsSupported, iPlayFormat)); |
|
132 } |
|
133 |
|
134 /* |
|
135 * |
|
136 * Initializes CMMFDevSoundProxy object to play and record PCM16 raw audio data |
|
137 * with sampling rate of 8 KHz. |
|
138 * |
|
139 * On completion of Initialization, calls InitializeComplete() on |
|
140 * aDevSoundObserver. |
|
141 * |
|
142 * Leaves on failure. |
|
143 * |
|
144 * @param "MDevSoundObserver& aDevSoundObserver" |
|
145 * A reference to DevSound Observer instance. |
|
146 * |
|
147 * @param "TMMFState aMode" |
|
148 * Mode for which this object will be used. |
|
149 * |
|
150 */ |
|
151 void CMMFDevSoundSvrImp::InitializeL(MDevSoundObserver& aDevSoundObserver, TMMFState aMode) |
|
152 |
|
153 { |
|
154 // if no HwDevice id specified, load default null implementation |
|
155 TUid rawUid = {KMmfUidHwDevicePCM16ToPCM16}; |
|
156 InitializeL(aDevSoundObserver, rawUid, aMode); |
|
157 __ASSERT_DEBUG(!(iHasPolicy&&(iMode == EMMFDevSoundStatePlaying)), Panic(TMMFDevSoundSessionPolicyNotInvalidated)); |
|
158 } |
|
159 |
|
160 /* |
|
161 * |
|
162 * Configure CMMFDevSoundProxy object for the settings in aConfig. |
|
163 * |
|
164 * Use this to set sampling rate, Encoding and Mono/Stereo. |
|
165 * |
|
166 * @param "TMMFCapabilities& aConfig" |
|
167 * Attribute values to which CMMFDevSoundProxy object will be configured to. |
|
168 * |
|
169 * As part of defect 20796, the iRecordFormat has been set under the iPlayFormat, |
|
170 * before it was not set at all. |
|
171 * |
|
172 */ |
|
173 void CMMFDevSoundSvrImp::SetConfigL(const TMMFCapabilities& aConfig) |
|
174 { |
|
175 TUint attributeValue = aConfig.iRate; |
|
176 // WINS supports from 8000 Hz to 96000 Hz |
|
177 // The ToneGenerator currently supports sample rate of 8000Hz only. |
|
178 if(iMode == EMMFDevSoundStateTonePlaying && (attributeValue != EMMFSampleRate8000Hz )) |
|
179 { |
|
180 User::Leave(KErrNotSupported); |
|
181 } |
|
182 |
|
183 if (attributeValue & EMMFSampleRate96000Hz) |
|
184 { |
|
185 iPlayFormat().iRate = 96000; |
|
186 iRecordFormat().iRate = 96000; |
|
187 iDeviceConfig.iRate = EMMFSampleRate96000Hz; |
|
188 } |
|
189 else if (attributeValue & EMMFSampleRate88200Hz) |
|
190 { |
|
191 iPlayFormat().iRate = 88200; |
|
192 iRecordFormat().iRate = 88200; |
|
193 iDeviceConfig.iRate = EMMFSampleRate88200Hz; |
|
194 } |
|
195 else if (attributeValue & EMMFSampleRate64000Hz) |
|
196 { |
|
197 iPlayFormat().iRate = 64000; |
|
198 iRecordFormat().iRate = 64000; |
|
199 iDeviceConfig.iRate = EMMFSampleRate64000Hz; |
|
200 } |
|
201 else if (attributeValue & EMMFSampleRate48000Hz) |
|
202 { |
|
203 iPlayFormat().iRate = 48000; |
|
204 iRecordFormat().iRate = 48000; |
|
205 iDeviceConfig.iRate = EMMFSampleRate48000Hz; |
|
206 } |
|
207 else if (attributeValue & EMMFSampleRate44100Hz) |
|
208 { |
|
209 iPlayFormat().iRate = 44100; |
|
210 iRecordFormat().iRate = 44100; |
|
211 iDeviceConfig.iRate = EMMFSampleRate44100Hz; |
|
212 } |
|
213 else if (attributeValue & EMMFSampleRate32000Hz) |
|
214 { |
|
215 iPlayFormat().iRate = 32000; |
|
216 iRecordFormat().iRate = 32000; |
|
217 iDeviceConfig.iRate = EMMFSampleRate32000Hz; |
|
218 } |
|
219 else if (attributeValue & EMMFSampleRate24000Hz) |
|
220 { |
|
221 iPlayFormat().iRate = |
|
222 iRecordFormat().iRate = 24000; |
|
223 iDeviceConfig.iRate = EMMFSampleRate24000Hz; |
|
224 } |
|
225 else if (attributeValue & EMMFSampleRate22050Hz) |
|
226 { |
|
227 iPlayFormat().iRate = 22050; |
|
228 iRecordFormat().iRate = 22050; |
|
229 iDeviceConfig.iRate = EMMFSampleRate22050Hz; |
|
230 } |
|
231 else if (attributeValue & EMMFSampleRate16000Hz) |
|
232 { |
|
233 iPlayFormat().iRate = 16000; |
|
234 iRecordFormat().iRate = 16000; |
|
235 iDeviceConfig.iRate = EMMFSampleRate16000Hz; |
|
236 } |
|
237 else if (attributeValue & EMMFSampleRate12000Hz) |
|
238 { |
|
239 iPlayFormat().iRate = |
|
240 iRecordFormat().iRate = 12000; |
|
241 iDeviceConfig.iRate = EMMFSampleRate12000Hz; |
|
242 } |
|
243 else if (attributeValue & EMMFSampleRate11025Hz) |
|
244 { |
|
245 iPlayFormat().iRate = 11025; |
|
246 iRecordFormat().iRate = 11025; |
|
247 iDeviceConfig.iRate = EMMFSampleRate11025Hz; |
|
248 } |
|
249 else if (attributeValue & EMMFSampleRate8000Hz) |
|
250 { |
|
251 iPlayFormat().iRate = 8000; |
|
252 iRecordFormat().iRate = 8000; |
|
253 iDeviceConfig.iRate = EMMFSampleRate8000Hz; |
|
254 } |
|
255 else if (attributeValue) |
|
256 { //if no attribute value assume its not set |
|
257 User::Leave(KErrNotSupported); |
|
258 } |
|
259 |
|
260 attributeValue = aConfig.iEncoding; |
|
261 // Map from MMF Encoding enums to RMdaDevSound enum |
|
262 if(attributeValue & EMMFSoundEncoding8BitPCM) |
|
263 { |
|
264 iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM; |
|
265 iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM; |
|
266 iDeviceConfig.iEncoding = EMMFSoundEncoding8BitPCM; |
|
267 } |
|
268 else if(attributeValue & EMMFSoundEncoding8BitALaw) |
|
269 { |
|
270 iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw; |
|
271 iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw; |
|
272 iDeviceConfig.iEncoding = EMMFSoundEncoding8BitALaw; |
|
273 } |
|
274 else if(attributeValue & EMMFSoundEncoding8BitMuLaw) |
|
275 { |
|
276 iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw; |
|
277 iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw; |
|
278 iDeviceConfig.iEncoding = EMMFSoundEncoding8BitMuLaw; |
|
279 } |
|
280 else if(attributeValue & EMMFSoundEncoding16BitPCM) |
|
281 { |
|
282 iPlayFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; |
|
283 iRecordFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; |
|
284 iDeviceConfig.iEncoding = EMMFSoundEncoding16BitPCM; |
|
285 } |
|
286 else if (attributeValue) |
|
287 { //if no attribute value assume its not set |
|
288 User::Leave(KErrNotSupported); |
|
289 } |
|
290 |
|
291 // Mono/Stereo settings |
|
292 attributeValue = aConfig.iChannels; |
|
293 if(iMode == EMMFDevSoundStateTonePlaying && (attributeValue != EMMFMono )) |
|
294 { |
|
295 User::Leave(KErrNotSupported); |
|
296 } |
|
297 if(attributeValue & EMMFStereo) |
|
298 { |
|
299 iPlayFormat().iChannels = 2; |
|
300 iRecordFormat().iChannels = 2; |
|
301 iDeviceConfig.iChannels = EMMFStereo; |
|
302 } |
|
303 else if(attributeValue & EMMFMono) |
|
304 { |
|
305 iPlayFormat().iChannels = 1; |
|
306 iRecordFormat().iChannels = 1; |
|
307 iDeviceConfig.iChannels = EMMFMono; |
|
308 } |
|
309 else if (attributeValue) |
|
310 { //if no attribute value assume its not set |
|
311 User::Leave(KErrNotSupported); |
|
312 } |
|
313 } |
|
314 |
|
315 /* |
|
316 * |
|
317 * Changes the current playback volume to a specified value. |
|
318 * |
|
319 * The volume can be changed before or during playback and is effective |
|
320 * immediately. |
|
321 * |
|
322 * @param "TInt aVolume" |
|
323 * The volume setting. This can be any value from zero to the value |
|
324 * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the |
|
325 * volume is not within this range, the volume is automatically set to |
|
326 * minimum or maximum value based on the value that is being passed. |
|
327 * Setting a zero value mutes the sound. Setting the maximum value |
|
328 * results in the loudest possible sound. |
|
329 * |
|
330 */ |
|
331 void CMMFDevSoundSvrImp::SetVolume(TInt aVolume) |
|
332 { |
|
333 |
|
334 // Check and make sure that the volume is in valid range |
|
335 if (aVolume < 0) |
|
336 aVolume = 0; |
|
337 |
|
338 if (aVolume > MaxVolume()) |
|
339 aVolume = MaxVolume(); |
|
340 |
|
341 iVolume = aVolume; |
|
342 |
|
343 SetDeviceVolume(iVolume); |
|
344 } |
|
345 |
|
346 /* |
|
347 * |
|
348 * Changes the current recording gain to a specified value. |
|
349 * |
|
350 * The gain can be changed before or during recording and is effective |
|
351 * immediately. |
|
352 * |
|
353 * @param "TInt aGain" |
|
354 * The volume setting. This can be any value from zero to the value |
|
355 * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the |
|
356 * volume is not within this range, the gain is automatically set to |
|
357 * minimum or maximum value based on the value that is being passed. |
|
358 * Setting a zero value mutes the sound. Setting the maximum value |
|
359 * results in the loudest possible sound. |
|
360 * |
|
361 */ |
|
362 void CMMFDevSoundSvrImp::SetGain(TInt aGain) |
|
363 { |
|
364 // make sure it falls with the correct range |
|
365 TInt maxGain = iRecordFormatsSupported().iMaxVolume; |
|
366 if (aGain > maxGain) |
|
367 aGain = maxGain; |
|
368 else if (aGain < 0) |
|
369 aGain = 0; |
|
370 iGain = aGain; |
|
371 SetDeviceRecordLevel(iGain); |
|
372 } |
|
373 |
|
374 /* |
|
375 * |
|
376 * Sets the speaker balance for playing. |
|
377 * |
|
378 * The speaker balance can be changed before or during playback and is |
|
379 * effective immediately. |
|
380 * |
|
381 * @param "TInt& aLeftPercentage" |
|
382 * On return contains left speaker volume perecentage. This can be any |
|
383 * value from zero to 100. Setting a zero value mutes the sound on left |
|
384 * speaker. |
|
385 * |
|
386 * @param "TInt& aRightPercentage" |
|
387 * On return contains right speaker volume perecentage. This can be any |
|
388 * value from zero to 100. Setting a zero value mutes the sound on |
|
389 * right speaker. |
|
390 * |
|
391 */ |
|
392 void CMMFDevSoundSvrImp::SetPlayBalanceL(TInt aLeftPercentage, TInt aRightPercentage) |
|
393 { |
|
394 if (aLeftPercentage < 0) |
|
395 aLeftPercentage = 0; |
|
396 else if (aLeftPercentage > 100) |
|
397 aLeftPercentage = 100; |
|
398 if (aRightPercentage < 0) |
|
399 aRightPercentage = 0; |
|
400 else if (aRightPercentage > 100) |
|
401 aRightPercentage = 100; |
|
402 iLeftPlayBalance = aLeftPercentage; |
|
403 iRightPlayBalance = aRightPercentage; |
|
404 } |
|
405 |
|
406 /* |
|
407 * |
|
408 * Sets the microphone gain balance for recording. |
|
409 * |
|
410 * The microphone gain balance can be changed before or during recording and |
|
411 * is effective immediately. |
|
412 * |
|
413 * @param "TInt aLeftPercentage" |
|
414 * Left microphone gain precentage. This can be any value from zero to |
|
415 * 100. Setting a zero value mutes the gain on left microphone. |
|
416 * |
|
417 * @param "TInt aRightPercentage" |
|
418 * Right microphone gain precentage. This can be any value from zero to |
|
419 * 100. Setting a zero value mutes the gain on right microphone. |
|
420 * |
|
421 */ |
|
422 void CMMFDevSoundSvrImp::SetRecordBalanceL(TInt aLeftPercentage, TInt aRightPercentage) |
|
423 { |
|
424 if (aLeftPercentage < 0) |
|
425 aLeftPercentage = 0; |
|
426 else if (aLeftPercentage > 100) |
|
427 aLeftPercentage = 100; |
|
428 if (aRightPercentage < 0) |
|
429 aRightPercentage = 0; |
|
430 else if (aRightPercentage > 100) |
|
431 aRightPercentage = 100; |
|
432 iLeftRecordBalance = aLeftPercentage; |
|
433 iRightRecordBalance = aRightPercentage; |
|
434 } |
|
435 |
|
436 /* |
|
437 * |
|
438 * Initializes audio device and start play process. This method queries and |
|
439 * acquires the audio policy before initializing audio device. If there was an |
|
440 * error during policy initialization, PlayError() method will be called on |
|
441 * the observer with error code KErrAccessDenied, otherwise BufferToBeFilled() |
|
442 * method will be called with a buffer reference. After reading data into the |
|
443 * buffer reference passed, the client should call PlayData() to play data. |
|
444 * |
|
445 * The amount of data that can be played is specified in |
|
446 * CMMFBuffer::RequestSize(). Any data that is read into buffer beyond this |
|
447 * size will be ignored. |
|
448 * |
|
449 * Leaves on failure. |
|
450 * |
|
451 */ |
|
452 void CMMFDevSoundSvrImp::PlayInitL() |
|
453 { |
|
454 if (!iDevSoundObserver) |
|
455 User::Leave(KErrNotReady); |
|
456 |
|
457 if (iAudioPolicyPrioritySettings.iState == EMMFStatePlayData) |
|
458 { |
|
459 // If policy has not been obtaing then ignore the request. |
|
460 // If it has then do a stop and start action on HW device |
|
461 // without informing policy. |
|
462 |
|
463 if (iHasPolicy) |
|
464 { |
|
465 if (iCMMFHwDevice) |
|
466 { |
|
467 TInt err = iCMMFHwDevice->Stop(); |
|
468 if (err == KErrNone) |
|
469 { |
|
470 err = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow); |
|
471 } |
|
472 |
|
473 if (err != KErrNone) |
|
474 { |
|
475 Error(err); |
|
476 } |
|
477 } |
|
478 } |
|
479 return; |
|
480 } |
|
481 |
|
482 // Get audio policy |
|
483 iAudioPolicyPrioritySettings.iState = EMMFStatePlayData; |
|
484 RequestPolicy(); |
|
485 } |
|
486 |
|
487 /* |
|
488 * |
|
489 * Initializes audio device and start record process. |
|
490 * This method: |
|
491 * 1. Queries and acquires the audio policy before initializing audio device. |
|
492 * If there was an error during policy initialization, RecordError() method will |
|
493 * be called on the observer with error code KErrAccessDenied, otherwise BufferToBeEmptied() |
|
494 * method will be called with a buffer reference. This buffer contains recorded |
|
495 * or encoded data. After processing data in the buffer reference passed, the |
|
496 * client should call RecordData() to continue recording process. |
|
497 * |
|
498 * 2. Checks if the requesting client process has a UserEnvironment capability. |
|
499 * If it does not, the audio device will not be initialized and an error |
|
500 * code KErrAccessDenied will be sent to the client. |
|
501 * |
|
502 * The amount of data that is available is specified in |
|
503 * CMMFBuffer::RequestSize(). |
|
504 * |
|
505 * Leaves on failure. |
|
506 * |
|
507 */ |
|
508 void CMMFDevSoundSvrImp::RecordInitL(const RMmfIpcMessage& aMessage) |
|
509 { |
|
510 if (!iDevSoundObserver) |
|
511 User::Leave(KErrNotReady); |
|
512 |
|
513 // Checkes if the client has the UserEnvironment capability |
|
514 if (!aMessage.HasCapability(ECapabilityUserEnvironment)) |
|
515 { |
|
516 User::Leave(KErrPermissionDenied); |
|
517 } |
|
518 |
|
519 if (iAudioPolicyPrioritySettings.iState == EMMFStateRecordData) |
|
520 { |
|
521 if (iHasPolicy) |
|
522 { |
|
523 if (iCMMFHwDevice) |
|
524 { |
|
525 TInt err = iCMMFHwDevice->Stop(); |
|
526 if (err == KErrNone) |
|
527 { |
|
528 err = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow); |
|
529 } |
|
530 |
|
531 if (err != KErrNone) |
|
532 { |
|
533 Error(err); |
|
534 } |
|
535 |
|
536 if (iHwDeviceBuffer) |
|
537 { |
|
538 iHwDeviceBuffer->SetLastBuffer(EFalse); |
|
539 } |
|
540 } |
|
541 } |
|
542 |
|
543 return; |
|
544 } |
|
545 |
|
546 // Get audio policy |
|
547 iAudioPolicyPrioritySettings.iState = EMMFStateRecordData; |
|
548 RequestPolicy(); |
|
549 } |
|
550 |
|
551 /* |
|
552 * |
|
553 * Plays data in the buffer at the current volume. The client should fill |
|
554 * the buffer with audio data before calling this method. The Observer gets |
|
555 * reference to buffer along with callback BufferToBeFilled(). When playing of |
|
556 * the audio sample is complete, successfully or otherwise, the method |
|
557 * PlayError() on observer is called. |
|
558 * |
|
559 */ |
|
560 TBool CMMFDevSoundSvrImp::PlayData(const RMmfIpcMessage& aMessage) |
|
561 { |
|
562 ASSERT(iDevSoundObserver); |
|
563 |
|
564 if (iAudioPolicyPrioritySettings.iState == EMMFStateStopped) |
|
565 { |
|
566 // Initialisation has been successful but an error (possibly underflow) has occurred |
|
567 // which the controller has yet to respond to and that has changed the state to stopped. |
|
568 // Allow the call to complete and processing to continue... |
|
569 return ETrue; |
|
570 } |
|
571 |
|
572 if((iAudioPolicyPrioritySettings.iState != EMMFStatePlayData) && (iAudioPolicyPrioritySettings.iState != EMMFStatePaused)) |
|
573 { |
|
574 PanicClient(aMessage, EMMFDevSoundPlayDataWithoutInitialize); |
|
575 return EFalse; |
|
576 } |
|
577 if (iMode== EMMFDevSoundStateIdle) |
|
578 { |
|
579 return ETrue; |
|
580 } |
|
581 TInt error = KErrNone; |
|
582 if(iCMMFHwDevice) |
|
583 { |
|
584 if (iPaused) |
|
585 { |
|
586 iPaused = EFalse; |
|
587 //note PlayData does not leave or return an error code so the Start() fails we cannot |
|
588 //report the error back at this point |
|
589 error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow);//restart hw device after pause |
|
590 } |
|
591 else if ((iMode == EMMFDevSoundStatePlaying) && iHasPolicy) |
|
592 { |
|
593 TInt len = iHwDeviceBuffer->Data().Length(); |
|
594 if (iHwDeviceBuffer->LastBuffer()) |
|
595 { |
|
596 iLastBufferReceived = ETrue; |
|
597 } |
|
598 // Pass the data buffer to HwDevice |
|
599 error = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); |
|
600 } |
|
601 } |
|
602 if (error != KErrNone) |
|
603 { |
|
604 Error(error); |
|
605 if(iCMMFHwDevice) |
|
606 { |
|
607 iCMMFHwDevice->Stop(); |
|
608 } |
|
609 |
|
610 } |
|
611 return ETrue; |
|
612 } |
|
613 |
|
614 /* |
|
615 * |
|
616 * Stops the ongoing operation (Play, Record, TonePlay, Convert) |
|
617 * |
|
618 */ |
|
619 void CMMFDevSoundSvrImp::Stop() |
|
620 { |
|
621 iPaused = EFalse; |
|
622 |
|
623 if (!iHasPolicy) |
|
624 { |
|
625 UpdatePolicyState(EMMFStateStopped); |
|
626 return; |
|
627 } |
|
628 |
|
629 // Stop the hw device first - this unloads sound drivers |
|
630 if (iCMMFHwDevice) |
|
631 { |
|
632 iCMMFHwDevice->Stop(); |
|
633 } |
|
634 |
|
635 iDevSoundEventHandler->CancelReceiveEvents(); |
|
636 |
|
637 UpdatePolicyState(EMMFStateStopped); |
|
638 __ASSERT_DEBUG(!(iHasPolicy&&(iMode == EMMFDevSoundStatePlaying)), Panic(TMMFDevSoundSessionPolicyNotInvalidated)); |
|
639 } |
|
640 |
|
641 /* |
|
642 * |
|
643 * Temporarily Stops the ongoing operation (Play, Record, TonePlay, Convert) |
|
644 * |
|
645 */ |
|
646 void CMMFDevSoundSvrImp::Pause() |
|
647 { |
|
648 iPaused = ETrue; |
|
649 |
|
650 if (!iHasPolicy) |
|
651 { |
|
652 return; |
|
653 } |
|
654 |
|
655 // Pause the HW device first |
|
656 if (iCMMFHwDevice) |
|
657 { |
|
658 iCMMFHwDevice->Pause(); |
|
659 } |
|
660 } |
|
661 |
|
662 /* |
|
663 * |
|
664 * Returns the sample recorded so far. |
|
665 * |
|
666 * @return "TInt" |
|
667 * Returns the samples recorded. |
|
668 * |
|
669 */ |
|
670 TInt CMMFDevSoundSvrImp::SamplesRecorded() |
|
671 { |
|
672 TInt samples = 0; |
|
673 |
|
674 if(iRecordCustomInterface) |
|
675 { |
|
676 samples = iRecordCustomInterface->BytesRecorded(); |
|
677 if(NumberOfChannels() > 1) |
|
678 { |
|
679 samples /= NumberOfChannels(); |
|
680 } |
|
681 if(BytesPerAudioSample() > 1) |
|
682 { |
|
683 samples /= BytesPerAudioSample(); |
|
684 } |
|
685 } |
|
686 |
|
687 return samples; |
|
688 } |
|
689 |
|
690 /* |
|
691 * |
|
692 * Returns the sample played so far. |
|
693 * |
|
694 * @return "TInt" |
|
695 * Returns the samples recorded. |
|
696 * |
|
697 */ |
|
698 TInt CMMFDevSoundSvrImp::SamplesPlayed() |
|
699 { |
|
700 TInt samples = 0; |
|
701 if(iPlayCustomInterface) |
|
702 { |
|
703 TUint bytesPlayed = iPlayCustomInterface->BytesPlayed(); |
|
704 if (bytesPlayed) |
|
705 iPlayedBytesCount = bytesPlayed; |
|
706 |
|
707 samples = iPlayedBytesCount; |
|
708 if(NumberOfChannels() > 1) |
|
709 samples /= NumberOfChannels(); |
|
710 |
|
711 if(BytesPerAudioSample() > 1) |
|
712 samples /= BytesPerAudioSample(); |
|
713 } |
|
714 //note always pcm16 becuase the iPlayedBytesCount originates from |
|
715 //RMdaDevSound which is always pcm16 |
|
716 return samples; //each sample is 2 bytes |
|
717 } |
|
718 |
|
719 |
|
720 /* |
|
721 * |
|
722 * Initializes audio device and start playing tone. Tone is played with |
|
723 * frequency and for duration specified. |
|
724 * |
|
725 * Leaves on failure. |
|
726 * |
|
727 * @param "TInt aFrequency" |
|
728 * Frequency at with the tone will be played. |
|
729 * |
|
730 * @param "TTimeIntervalMicroSeconds& aDuration" |
|
731 * The period over which the tone will be played. A zero value causes |
|
732 * the no tone to be played (Verify this with test app). |
|
733 * |
|
734 */ |
|
735 void CMMFDevSoundSvrImp::PlayToneL(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration) |
|
736 { |
|
737 if (iMode != EMMFDevSoundStateTonePlaying) |
|
738 { |
|
739 User::Leave(KErrNotSupported); //tone playing only supported in tone play state |
|
740 } |
|
741 |
|
742 // Check whether frequency and duration is valid or not |
|
743 TInt64 zeroInt64(0); |
|
744 if ((aFrequency<0) || (aDuration.Int64() < zeroInt64)) |
|
745 { |
|
746 User::Leave(KErrArgument); |
|
747 } |
|
748 |
|
749 if (!iDevSoundObserver) |
|
750 { |
|
751 User::Leave(KErrNotReady); |
|
752 } |
|
753 |
|
754 iToneGen.SetFrequencyAndDuration(aFrequency,aDuration); |
|
755 |
|
756 // Get audio policy |
|
757 iAudioPolicyPrioritySettings.iState = EMMFStatePlayTone; |
|
758 RequestPolicy(); |
|
759 } |
|
760 |
|
761 /* |
|
762 * Initializes audio device and start playing a dual tone. |
|
763 * The tone consists of two sine waves of different frequencies summed together |
|
764 * Dual Tone is played with specified frequencies and for specified duration. |
|
765 * |
|
766 * @param "aFrequencyOne" |
|
767 * First frequency of dual tone |
|
768 * |
|
769 * @param "aFrequencyTwo" |
|
770 * Second frequency of dual tone |
|
771 * |
|
772 * @param "aDuration" |
|
773 * The period over which the tone will be played. A zero value causes |
|
774 * the no tone to be played (Verify this with test app). |
|
775 */ |
|
776 void CMMFDevSoundSvrImp::PlayDualToneL(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration) |
|
777 { |
|
778 if (!iDevSoundObserver) |
|
779 { |
|
780 User::Leave(KErrNotReady); |
|
781 } |
|
782 |
|
783 // Check whether frequencies and duration are valid or not |
|
784 TInt64 zeroInt64(0); |
|
785 if ((aFrequencyOne<0) || (aFrequencyTwo<0) || (aDuration.Int64() < zeroInt64)) |
|
786 { |
|
787 iDevSoundObserver->ToneFinished(KErrArgument); |
|
788 return; |
|
789 } |
|
790 |
|
791 |
|
792 iDualToneGen.SetFrequencyAndDuration(aFrequencyOne, aFrequencyTwo, aDuration); |
|
793 |
|
794 // Get audio policy |
|
795 iAudioPolicyPrioritySettings.iState = EMMFStatePlayDualTone; |
|
796 RequestPolicy(); |
|
797 } |
|
798 |
|
799 /* |
|
800 * |
|
801 * Initializes audio device and start playing DTMF string aDTMFString. |
|
802 * |
|
803 * Leaves on failure. |
|
804 * |
|
805 * @param "TDesC& aDTMFString" |
|
806 * DTMF sequence in a descriptor. |
|
807 * |
|
808 */ |
|
809 void CMMFDevSoundSvrImp::PlayDTMFStringL(const TDesC& aDTMFString) |
|
810 { |
|
811 if (!iDevSoundObserver) |
|
812 User::Leave(KErrNotReady); |
|
813 |
|
814 if (iMode!= EMMFDevSoundStateTonePlaying) |
|
815 User::Leave(KErrNotSupported); //tone playing only supported in tone play state |
|
816 |
|
817 iDTMFGen.SetString(aDTMFString); |
|
818 |
|
819 // Get audio policy |
|
820 iAudioPolicyPrioritySettings.iState = EMMFStatePlayDTMFString; |
|
821 RequestPolicy(); |
|
822 } |
|
823 |
|
824 /* |
|
825 * |
|
826 * Initializes audio device and start playing tone sequence. |
|
827 * |
|
828 * Leaves on failure. |
|
829 * |
|
830 * @param "TDesC8& aData" |
|
831 * Tone sequence in a descriptor. |
|
832 * |
|
833 */ |
|
834 void CMMFDevSoundSvrImp::PlayToneSequenceL(const TDesC8& aData) |
|
835 { |
|
836 if (!iDevSoundObserver) |
|
837 User::Leave(KErrNotReady); |
|
838 |
|
839 if (iMode!= EMMFDevSoundStateTonePlaying) |
|
840 User::Leave(KErrNotSupported); //tone playing only supported in tone play state |
|
841 |
|
842 // Check whether the sequence is valid or not |
|
843 if (!iDevSoundUtil->RecognizeSequence(aData)) |
|
844 User::Leave(KErrCorrupt); |
|
845 |
|
846 iSequenceGen.SetSequenceData(aData); |
|
847 |
|
848 // Get audio policy |
|
849 iAudioPolicyPrioritySettings.iState = EMMFStatePlayToneSequence; |
|
850 RequestPolicy(); |
|
851 } |
|
852 |
|
853 /* |
|
854 * |
|
855 * Initializes audio device and start playing the specified pre-defined tone |
|
856 * sequence. |
|
857 * |
|
858 * Leaves on failure. |
|
859 * |
|
860 * @param "TInt aSequenceNumber" |
|
861 * The index identifying the specific pre-defined tone sequence. Index |
|
862 * values are relative to zero. |
|
863 * This can be any value from zero to the value returned by a call to |
|
864 * FixedSequenceCount() - 1. |
|
865 * The function raises a panic if sequence number is not within this |
|
866 * range. |
|
867 * |
|
868 * @see FixesSequenceCount() |
|
869 * |
|
870 */ |
|
871 void CMMFDevSoundSvrImp::PlayFixedSequenceL(TInt aSequenceNumber) |
|
872 { |
|
873 if (!iDevSoundObserver) |
|
874 User::Leave(KErrNotReady); |
|
875 |
|
876 if (iMode!= EMMFDevSoundStateTonePlaying) |
|
877 User::Leave(KErrNotSupported); //tone playing only supported in tone play state |
|
878 |
|
879 ASSERT((aSequenceNumber >= 0)&&(aSequenceNumber < iFixedSequences->Count())); |
|
880 |
|
881 iFixedSequence.Set(iFixedSequences->MdcaPoint(aSequenceNumber)); |
|
882 iSequenceGen.SetSequenceData(iFixedSequence); |
|
883 |
|
884 // Get audio policy |
|
885 iAudioPolicyPrioritySettings.iState = EMMFStatePlayToneSequence; |
|
886 RequestPolicy(); |
|
887 } |
|
888 |
|
889 /* |
|
890 * |
|
891 * Defines the duration of tone on, tone off and tone pause to be used during the |
|
892 * DTMF tone playback operation. |
|
893 * |
|
894 * Supported only during tone playing. |
|
895 * |
|
896 * @param "TTimeIntervalMicroSeconds32& aToneOnLength" |
|
897 * The period over which the tone will be played. If this is set to |
|
898 * zero, then the tone is not played. |
|
899 * |
|
900 * @param "TTimeIntervalMicroSeconds32& aToneOffLength" |
|
901 * The period over which the no tone will be played. |
|
902 * |
|
903 * @param "TTimeIntervalMicroSeconds32& aPauseLength" |
|
904 * The period over which the tone playing will be paused. |
|
905 * |
|
906 */ |
|
907 void CMMFDevSoundSvrImp::SetDTMFLengths(TTimeIntervalMicroSeconds32& aToneOnLength, |
|
908 TTimeIntervalMicroSeconds32& aToneOffLength, |
|
909 TTimeIntervalMicroSeconds32& aPauseLength) |
|
910 { |
|
911 |
|
912 if(aToneOnLength.Int() < KMdaInfiniteDurationDTMFToneOnLength) |
|
913 aToneOnLength = TTimeIntervalMicroSeconds32(0); |
|
914 if(aToneOffLength.Int() < 0) |
|
915 aToneOffLength = TTimeIntervalMicroSeconds32(0); |
|
916 if(aPauseLength.Int() < 0) |
|
917 aPauseLength = TTimeIntervalMicroSeconds32(0); |
|
918 |
|
919 iDTMFGen.SetToneDurations(aToneOnLength,aToneOffLength,aPauseLength); |
|
920 } |
|
921 |
|
922 /* |
|
923 * |
|
924 * Defines the period over which the volume level is to rise smoothly from |
|
925 * nothing to the normal volume level. |
|
926 * |
|
927 * @param "TTimeIntervalMicroSeconds& aRampDuration" |
|
928 * The period over which the volume is to rise. A zero value causes |
|
929 * the tone sample to be played at the normal level for the full |
|
930 * duration of the playback. A value, which is longer than the duration |
|
931 * of the tone sample, that the sample never reaches its normal |
|
932 * volume level. |
|
933 * |
|
934 * |
|
935 */ |
|
936 void CMMFDevSoundSvrImp::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration) |
|
937 { |
|
938 // save ramp duration for tone generator |
|
939 iRampDuration = aRampDuration; |
|
940 |
|
941 SetDeviceVolumeRamp(iRampDuration); |
|
942 } |
|
943 |
|
944 /** |
|
945 * Sets volume ramp on HwDevice. |
|
946 */ |
|
947 TInt CMMFDevSoundSvrImp::SetDeviceVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration) |
|
948 { |
|
949 TInt error = KErrNone; |
|
950 if (iPlayCustomInterface) |
|
951 iPlayCustomInterface->SetVolumeRamp(aRampDuration); |
|
952 else |
|
953 error = KErrNotReady; |
|
954 return error; |
|
955 } |
|
956 |
|
957 /** |
|
958 * @see sounddevice.h |
|
959 */ |
|
960 void CMMFDevSoundSvrImp::GetSupportedInputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& /*aPrioritySettings*/) const |
|
961 { |
|
962 //aPrioritySettings not used on ref DevSound |
|
963 //search for playing datatypes |
|
964 iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes, EMMFStatePlaying); |
|
965 #ifdef SYMBIAN_MULTIMEDIA_CODEC_API |
|
966 // append list of codec plugins |
|
967 iDevSoundUtil->SeekCodecPluginsL(aSupportedDataTypes, EMMFStatePlaying, ETrue); |
|
968 #endif // SYMBIAN_MULTIMEDIA_CODEC_API |
|
969 } |
|
970 |
|
971 /** |
|
972 * @see sounddevice.h |
|
973 */ |
|
974 void CMMFDevSoundSvrImp::GetSupportedOutputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& /*aPrioritySettings*/) const |
|
975 { |
|
976 //aPrioritySettings not used on ref DevSound |
|
977 // search for recording datatypes |
|
978 iDevSoundUtil->SeekHwDevicePluginsL(aSupportedDataTypes, EMMFStateRecording); |
|
979 #ifdef SYMBIAN_MULTIMEDIA_CODEC_API |
|
980 // append list of codec plugins |
|
981 iDevSoundUtil->SeekCodecPluginsL(aSupportedDataTypes, EMMFStateRecording, ETrue); |
|
982 #endif // SYMBIAN_MULTIMEDIA_CODEC_API |
|
983 } |
|
984 |
|
985 TInt CMMFDevSoundSvrImp::RegisterAsClient(TUid aEventType, const TDesC8& aNotificationRegistrationData) |
|
986 { |
|
987 return iAudioPolicyProxy->RequestResourceNotification(aEventType,aNotificationRegistrationData); |
|
988 } |
|
989 |
|
990 TInt CMMFDevSoundSvrImp::CancelRegisterAsClient(TUid aEventType) |
|
991 { |
|
992 return iAudioPolicyProxy->CancelRequestResourceNotification(aEventType); |
|
993 } |
|
994 |
|
995 TInt CMMFDevSoundSvrImp::GetResourceNotificationData(TUid aEventType, TDes8& aNotificationData) |
|
996 { |
|
997 TInt err = KErrNone; |
|
998 err = iAudioPolicyProxy->IsRegisteredResourceNotification(aEventType); |
|
999 if(err == KErrNone) |
|
1000 { |
|
1001 TMMFTimeIntervalMicroSecondsPckg pckg = TTimeIntervalMicroSeconds(SamplesPlayed()); |
|
1002 aNotificationData.Copy(pckg); |
|
1003 } |
|
1004 return err; |
|
1005 } |
|
1006 |
|
1007 TInt CMMFDevSoundSvrImp::WillResumePlay() |
|
1008 { |
|
1009 return iAudioPolicyProxy->StopNotification(); |
|
1010 } |
|
1011 |
|
1012 TInt CMMFDevSoundSvrImp::EmptyBuffers() |
|
1013 { |
|
1014 TInt err = KErrNone; |
|
1015 if (iMode != EMMFStatePlaying) |
|
1016 { |
|
1017 return KErrNotSupported; |
|
1018 } |
|
1019 if (!iCMMFHwDevice) |
|
1020 { |
|
1021 return KErrNotReady; |
|
1022 } |
|
1023 MEmptyBuffersCustomInterface* emptybuffers = reinterpret_cast<MEmptyBuffersCustomInterface*>(iCMMFHwDevice->CustomInterface(KEmptyBuffersCustomInterfaceTypeUid)); |
|
1024 if (emptybuffers) |
|
1025 { |
|
1026 err = emptybuffers->EmptyBuffers(); |
|
1027 } |
|
1028 else |
|
1029 { |
|
1030 err = KErrNotSupported; |
|
1031 } |
|
1032 return err; |
|
1033 } |
|
1034 |
|
1035 TInt CMMFDevSoundSvrImp::GetTimePlayed(TTimeIntervalMicroSeconds& aTime) |
|
1036 { |
|
1037 TInt err = KErrNone; |
|
1038 TTimeIntervalMicroSeconds time(0); |
|
1039 if(iCMMFHwDevice) |
|
1040 { |
|
1041 if(!iTimePlayedCustomInterface) |
|
1042 { |
|
1043 iTimePlayedCustomInterface = reinterpret_cast<MTimePlayedCustomInterface*>(iCMMFHwDevice->CustomInterface(KTimePlayedCustomInterfaceTypeUid)); |
|
1044 if(iTimePlayedCustomInterface == NULL) |
|
1045 { |
|
1046 return KErrNotSupported; |
|
1047 } |
|
1048 } |
|
1049 err = iTimePlayedCustomInterface->GetTimePlayed(time); |
|
1050 if(err == KErrNone && time.Int64() > 0) |
|
1051 { |
|
1052 iTimePlayed = time.Int64(); |
|
1053 } |
|
1054 } |
|
1055 aTime = iTimePlayed.Int64(); |
|
1056 return err; |
|
1057 } |
|
1058 |
|
1059 /******************************************************************************** |
|
1060 * Implementations of Non Exported public functions begins here * |
|
1061 ********************************************************************************/ |
|
1062 |
|
1063 // |
|
1064 // Audio Policy specific implementation begins here // |
|
1065 // |
|
1066 |
|
1067 /* |
|
1068 * |
|
1069 * Called by Audio Policy Server when a request to play is approved by the |
|
1070 * Audio Policy Server. |
|
1071 * |
|
1072 * Leaves on failure??. |
|
1073 * |
|
1074 */ |
|
1075 void CMMFDevSoundSvrImp::StartPlayDataL() |
|
1076 { |
|
1077 ASSERT(iMode== EMMFDevSoundStatePlaying); |
|
1078 if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) |
|
1079 { |
|
1080 return; |
|
1081 } |
|
1082 iHasPolicy = ETrue; |
|
1083 |
|
1084 TInt error = KErrNone; |
|
1085 |
|
1086 if(iCMMFHwDevice) |
|
1087 { |
|
1088 UpdatePolicyState(EMMFStatePlayData); |
|
1089 // Set volume and play format values |
|
1090 error = SetPlayFormat(iPlayFormat); |
|
1091 if (error == KErrNone) |
|
1092 error = SetDeviceVolume(iVolume); |
|
1093 if (error == KErrNone) |
|
1094 error = SetDeviceVolumeRamp(iRampDuration); |
|
1095 |
|
1096 // Initialize attribute values |
|
1097 iPlayedBytesCount = 0; |
|
1098 iTimePlayed = 0; |
|
1099 iLastBufferReceived = EFalse; |
|
1100 |
|
1101 // Start HwDevice |
|
1102 if (error == KErrNone) |
|
1103 error = iCMMFHwDevice->Start(EDevDecode, EDevOutFlow); |
|
1104 } |
|
1105 else |
|
1106 error = KErrNotReady; |
|
1107 |
|
1108 if (error != KErrNone) |
|
1109 { |
|
1110 Error(error); |
|
1111 |
|
1112 } |
|
1113 } |
|
1114 |
|
1115 /* |
|
1116 * |
|
1117 * Called by Audio Policy Server when a request to record is approved by the |
|
1118 * Audio Policy Server. |
|
1119 * |
|
1120 * Leaves on failure. |
|
1121 * |
|
1122 */ |
|
1123 void CMMFDevSoundSvrImp::StartRecordDataL() |
|
1124 { |
|
1125 ASSERT(iMode== EMMFDevSoundStateRecording); |
|
1126 if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) |
|
1127 { |
|
1128 return; |
|
1129 } |
|
1130 iHasPolicy = ETrue; |
|
1131 |
|
1132 if(iCMMFHwDevice) |
|
1133 { |
|
1134 UpdatePolicyState(EMMFStateRecordData); |
|
1135 TInt error = KErrNone; |
|
1136 error = SetRecordFormat(iRecordFormat); |
|
1137 if (error != KErrNone) |
|
1138 { |
|
1139 Error(error); |
|
1140 return; |
|
1141 |
|
1142 } |
|
1143 error = SetDeviceRecordLevel(iGain); |
|
1144 if (error != KErrNone) |
|
1145 { |
|
1146 Error(error); |
|
1147 return; |
|
1148 |
|
1149 } |
|
1150 error = iCMMFHwDevice->Start(EDevEncode, EDevInFlow); |
|
1151 if (iHwDeviceBuffer) |
|
1152 iHwDeviceBuffer->SetLastBuffer(EFalse); |
|
1153 |
|
1154 if (error != KErrNone) |
|
1155 { |
|
1156 Error(error); |
|
1157 return; |
|
1158 } |
|
1159 } |
|
1160 else |
|
1161 iDevSoundObserver->RecordError(KErrNotReady); |
|
1162 } |
|
1163 |
|
1164 /* |
|
1165 * |
|
1166 * Called by Audio Policy Server when a request to play tone is approved by |
|
1167 * the Audio Policy Server. |
|
1168 * |
|
1169 * Leaves on failure. |
|
1170 * |
|
1171 */ |
|
1172 void CMMFDevSoundSvrImp::StartPlayToneL() |
|
1173 { |
|
1174 ASSERT(iMode == EMMFDevSoundStateTonePlaying); |
|
1175 if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) |
|
1176 { |
|
1177 return; |
|
1178 } |
|
1179 iHasPolicy = ETrue; |
|
1180 |
|
1181 if(iCMMFHwDevice) |
|
1182 { |
|
1183 UpdatePolicyState(EMMFStatePlayTone); |
|
1184 TInt error = KErrNone; |
|
1185 // Set volume and play format values |
|
1186 error = SetPlayFormat(iPlayFormat); |
|
1187 if (error != KErrNone) |
|
1188 { |
|
1189 Error(error); |
|
1190 return; |
|
1191 |
|
1192 } |
|
1193 if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) |
|
1194 error = SetDeviceVolume(iVolume); |
|
1195 else |
|
1196 error = KErrGeneral;//hw device should always be pcm16 for tone |
|
1197 |
|
1198 // turn off volume ramping - this is done in software below |
|
1199 if (error == KErrNone) |
|
1200 error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); |
|
1201 |
|
1202 if (error != KErrNone) |
|
1203 { |
|
1204 Error(error); |
|
1205 return; |
|
1206 |
|
1207 } |
|
1208 |
|
1209 // Initialize attribute values |
|
1210 iPlayedBytesCount = 0; |
|
1211 iTimePlayed = 0; |
|
1212 // Configure tone generator |
|
1213 iToneGen.Configure( |
|
1214 iPlayFormat().iRate, |
|
1215 iPlayFormat().iChannels, |
|
1216 iRepeatCount, |
|
1217 I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000), |
|
1218 I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000) |
|
1219 ); |
|
1220 |
|
1221 iCurrentGenerator = &iToneGen; |
|
1222 |
|
1223 // Start playback |
|
1224 DoPlayL(); |
|
1225 } |
|
1226 else |
|
1227 iDevSoundObserver->ToneFinished(KErrNotReady); |
|
1228 } |
|
1229 |
|
1230 /* |
|
1231 * |
|
1232 * Called by Audio Policy Server when a request to play a dual tone is approved by |
|
1233 * the Audio Policy Server. |
|
1234 * |
|
1235 */ |
|
1236 void CMMFDevSoundSvrImp::StartPlayDualToneL() |
|
1237 { |
|
1238 ASSERT(iMode == EMMFDevSoundStateTonePlaying); |
|
1239 if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) |
|
1240 { |
|
1241 return; |
|
1242 } |
|
1243 iHasPolicy = ETrue; |
|
1244 |
|
1245 if(iCMMFHwDevice) |
|
1246 { |
|
1247 UpdatePolicyState(EMMFStatePlayDualTone); |
|
1248 TInt error = KErrNone; |
|
1249 // Set volume and play format values |
|
1250 error = SetPlayFormat(iPlayFormat); |
|
1251 if (error != KErrNone) |
|
1252 { |
|
1253 Error(error); |
|
1254 return; |
|
1255 } |
|
1256 if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) |
|
1257 error = SetDeviceVolume(iVolume); |
|
1258 else |
|
1259 error = KErrGeneral;//hw device should always be pcm16 for tone |
|
1260 |
|
1261 // turn off volume ramping - this is done in software below |
|
1262 if (error == KErrNone) |
|
1263 error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); |
|
1264 |
|
1265 if (error != KErrNone) |
|
1266 { |
|
1267 Error(error); |
|
1268 return; |
|
1269 |
|
1270 } |
|
1271 |
|
1272 // Initialize attribute values |
|
1273 iPlayedBytesCount = 0; |
|
1274 iTimePlayed = 0; |
|
1275 // Configure dual tone generator |
|
1276 iDualToneGen.Configure( |
|
1277 iPlayFormat().iRate, |
|
1278 iPlayFormat().iChannels, |
|
1279 iRepeatCount, |
|
1280 I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/KOneMillionMicroSeconds), |
|
1281 I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/KOneMillionMicroSeconds) |
|
1282 ); |
|
1283 |
|
1284 iCurrentGenerator = &iDualToneGen; |
|
1285 |
|
1286 // Start playback |
|
1287 DoPlayL(); |
|
1288 } |
|
1289 else |
|
1290 iDevSoundObserver->ToneFinished(KErrNotReady); |
|
1291 } |
|
1292 |
|
1293 /* |
|
1294 * |
|
1295 * Called by Audio Policy Server when a request to play DTMF String is approved |
|
1296 * by the Audio Policy Server. |
|
1297 * |
|
1298 * Leaves on failure. |
|
1299 * |
|
1300 */ |
|
1301 void CMMFDevSoundSvrImp::StartPlayDTMFStringL() |
|
1302 { |
|
1303 ASSERT(iMode == EMMFDevSoundStateTonePlaying); |
|
1304 if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) |
|
1305 { |
|
1306 return; |
|
1307 } |
|
1308 iHasPolicy = ETrue; |
|
1309 |
|
1310 if(iCMMFHwDevice) |
|
1311 { |
|
1312 UpdatePolicyState(EMMFStatePlayDTMFString); |
|
1313 TInt error = KErrNone; |
|
1314 // Set volume and play format values |
|
1315 error = SetPlayFormat(iPlayFormat); |
|
1316 if (error != KErrNone) |
|
1317 { |
|
1318 Error(error); |
|
1319 return; |
|
1320 |
|
1321 } |
|
1322 error = SetDeviceVolume(iVolume); |
|
1323 |
|
1324 // turn off volume ramping - this is done in software below |
|
1325 if (error == KErrNone) |
|
1326 error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); |
|
1327 |
|
1328 if (error != KErrNone) |
|
1329 { |
|
1330 Error(error); |
|
1331 return; |
|
1332 } |
|
1333 |
|
1334 // Initialize attribute values |
|
1335 iPlayedBytesCount = 0; |
|
1336 iTimePlayed = 0; |
|
1337 iDTMFGen.Configure( |
|
1338 iPlayFormat().iRate, |
|
1339 iPlayFormat().iChannels, |
|
1340 iRepeatCount, |
|
1341 I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000), |
|
1342 I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000) |
|
1343 ); |
|
1344 |
|
1345 iCurrentGenerator = &iDTMFGen; |
|
1346 |
|
1347 // Start playback |
|
1348 //need to trap this as we can leave with KErrUnderflow |
|
1349 //if there was no data to play - the error has already |
|
1350 //been sent to the observer and we don't want to call RunError |
|
1351 TRAP(error,DoPlayL()); |
|
1352 if ((error != KErrUnderflow)&&(error != KErrNone)) |
|
1353 { |
|
1354 User::Leave(error); |
|
1355 } |
|
1356 } |
|
1357 else |
|
1358 iDevSoundObserver->ToneFinished(KErrNotReady); |
|
1359 } |
|
1360 |
|
1361 /* |
|
1362 * |
|
1363 * Called by Audio Policy Server when a request to play tone sequence is |
|
1364 * approved by the Audio Policy Server. |
|
1365 * |
|
1366 * Leaves on failure. |
|
1367 * |
|
1368 */ |
|
1369 void CMMFDevSoundSvrImp::StartPlayToneSequenceL() |
|
1370 { |
|
1371 ASSERT(iMode == EMMFDevSoundStateTonePlaying); |
|
1372 if(iAudioPolicyPrioritySettings.iState == EMMFStateStopped) |
|
1373 { |
|
1374 return; |
|
1375 } |
|
1376 iHasPolicy = ETrue; |
|
1377 |
|
1378 if(iCMMFHwDevice) |
|
1379 { |
|
1380 UpdatePolicyState(EMMFStatePlayToneSequence); |
|
1381 TInt error = KErrNone; |
|
1382 // Set volume and play format values |
|
1383 if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) |
|
1384 error = SetPlayFormat(iPlayFormat); |
|
1385 else error = KErrGeneral;//hw device should always be pcm16 for tone |
|
1386 if (error != KErrNone) |
|
1387 { |
|
1388 Error(error); |
|
1389 return; |
|
1390 } |
|
1391 |
|
1392 if (iHwDeviceID.iUid == KMmfUidHwDevicePCM16ToPCM16) |
|
1393 error = SetDeviceVolume(iVolume); |
|
1394 else |
|
1395 error = KErrGeneral;//hw device should always be pcm16 for tone |
|
1396 |
|
1397 // turn off volume ramping - this is done in software below |
|
1398 if (error == KErrNone) |
|
1399 error = SetDeviceVolumeRamp(TTimeIntervalMicroSeconds(0)); |
|
1400 |
|
1401 if (error != KErrNone) |
|
1402 { |
|
1403 Error(error); |
|
1404 return; |
|
1405 } |
|
1406 |
|
1407 // Initialize attribute values |
|
1408 iPlayedBytesCount = 0; |
|
1409 iTimePlayed = 0; |
|
1410 iSequenceGen.Configure( |
|
1411 iPlayFormat().iRate, |
|
1412 iPlayFormat().iChannels, |
|
1413 iRepeatCount, |
|
1414 I64LOW((iRepeatTrailingSilence.Int64()*iPlayFormat().iRate)/1000000), |
|
1415 I64LOW((iRampDuration.Int64()*iPlayFormat().iRate)/1000000) |
|
1416 ); |
|
1417 |
|
1418 iCurrentGenerator = &iSequenceGen; |
|
1419 |
|
1420 // Start playback |
|
1421 DoPlayL(); |
|
1422 } |
|
1423 else |
|
1424 iDevSoundObserver->ToneFinished(KErrNotReady); |
|
1425 } |
|
1426 |
|
1427 /* |
|
1428 * |
|
1429 * Called by Audio Policy Server when the current DevSound instance looses the |
|
1430 * policy because of another instance with a higher priority wants the device. |
|
1431 * |
|
1432 */ |
|
1433 void CMMFDevSoundSvrImp::SendEventToClient(const TMMFEvent& aEvent) |
|
1434 { |
|
1435 if (aEvent.iErrorCode != KErrNone) |
|
1436 { |
|
1437 iHasPolicy = EFalse; |
|
1438 if (iMode == EMMFDevSoundStatePlaying) |
|
1439 { |
|
1440 UpdateBytesPlayed(); |
|
1441 iDevSoundObserver->PlayError(aEvent.iErrorCode); |
|
1442 UpdatePolicyState(EMMFStateStopped); |
|
1443 } |
|
1444 else if (iMode == EMMFDevSoundStateRecording) |
|
1445 { |
|
1446 iDevSoundObserver->RecordError(aEvent.iErrorCode); |
|
1447 UpdatePolicyState(EMMFStateStopped); |
|
1448 } |
|
1449 else if (iMode == EMMFDevSoundStateTonePlaying) |
|
1450 { |
|
1451 iDevSoundObserver->ToneFinished(aEvent.iErrorCode); |
|
1452 } |
|
1453 iCMMFHwDevice->Stop();//unloads sound device |
|
1454 // Have audio Policy launch higher priority request |
|
1455 iAudioPolicyProxy->LaunchRequests(); |
|
1456 } |
|
1457 else |
|
1458 { |
|
1459 iHasPolicy = ETrue; |
|
1460 iDevSoundObserver->SendEventToClient(aEvent); |
|
1461 } |
|
1462 } |
|
1463 |
|
1464 |
|
1465 /** |
|
1466 * |
|
1467 * Sets volume on HwDevice. |
|
1468 * |
|
1469 * @return "TInt" |
|
1470 * Error value returned by HwDevice. |
|
1471 * |
|
1472 */ |
|
1473 TInt CMMFDevSoundSvrImp::SetDeviceVolume(TInt aVolume) |
|
1474 { |
|
1475 TInt error = KErrNone; |
|
1476 if (iPlayCustomInterface) |
|
1477 iPlayCustomInterface->SetVolume(aVolume); |
|
1478 else error = KErrNotReady; |
|
1479 return error; |
|
1480 } |
|
1481 |
|
1482 /** |
|
1483 * |
|
1484 * Sets PlayFormat on HwDevice. |
|
1485 * |
|
1486 * |
|
1487 * @return "TInt" |
|
1488 * Error value returned by HwDevice. |
|
1489 * |
|
1490 */ |
|
1491 TInt CMMFDevSoundSvrImp::SetPlayFormat(RMdaDevSound::TCurrentSoundFormatBuf& aPlayFormat) |
|
1492 { |
|
1493 TInt error = KErrNone; |
|
1494 if (iCMMFHwDevice) |
|
1495 { |
|
1496 TTaskConfig taskConfig; |
|
1497 taskConfig.iUid = KUidRefDevSoundTaskConfig; |
|
1498 taskConfig.iRate = aPlayFormat().iRate; |
|
1499 |
|
1500 if (aPlayFormat().iChannels == 1) |
|
1501 { |
|
1502 taskConfig.iStereoMode = ETaskMono; |
|
1503 } |
|
1504 else if (aPlayFormat().iChannels == 2) |
|
1505 { |
|
1506 taskConfig.iStereoMode = ETaskInterleaved; |
|
1507 } |
|
1508 else |
|
1509 { |
|
1510 return KErrArgument; |
|
1511 } |
|
1512 |
|
1513 error = iCMMFHwDevice->SetConfig(taskConfig); |
|
1514 //note the iEncoding and iBufferSize are already determined by the |
|
1515 //CMMFHwDevice plugin and so are not set. |
|
1516 } |
|
1517 else |
|
1518 { |
|
1519 error = KErrNotReady; |
|
1520 } |
|
1521 return error; |
|
1522 } |
|
1523 |
|
1524 |
|
1525 /** |
|
1526 * |
|
1527 * Sets RecordFormat on HwDevice. |
|
1528 * |
|
1529 * |
|
1530 * @return "TInt" |
|
1531 * Error value returned by HwDevice. |
|
1532 * |
|
1533 */ |
|
1534 TInt CMMFDevSoundSvrImp::SetRecordFormat(RMdaDevSound::TCurrentSoundFormatBuf& aRecordFormat) |
|
1535 { |
|
1536 TInt error = KErrNone; |
|
1537 if (iCMMFHwDevice) |
|
1538 { |
|
1539 TTaskConfig taskConfig; |
|
1540 taskConfig.iUid = KUidRefDevSoundTaskConfig; |
|
1541 taskConfig.iRate = aRecordFormat().iRate; |
|
1542 |
|
1543 if (aRecordFormat().iChannels == 1) |
|
1544 { |
|
1545 taskConfig.iStereoMode = ETaskMono; |
|
1546 } |
|
1547 else if (aRecordFormat().iChannels == 2) |
|
1548 { |
|
1549 taskConfig.iStereoMode = ETaskInterleaved; |
|
1550 } |
|
1551 else |
|
1552 { |
|
1553 return KErrArgument; |
|
1554 } |
|
1555 |
|
1556 error = iCMMFHwDevice->SetConfig(taskConfig); |
|
1557 //note the iEncoding and iBufferSize are already determined by the |
|
1558 //CMMFHwDevice plugin and so are not set. |
|
1559 } |
|
1560 else |
|
1561 { |
|
1562 error = KErrNotReady; |
|
1563 } |
|
1564 return error; |
|
1565 } |
|
1566 |
|
1567 |
|
1568 /** |
|
1569 * |
|
1570 * Sets record level on HwDevice. |
|
1571 * |
|
1572 * |
|
1573 * @return "TInt" |
|
1574 * Error value returned by HwDevice. |
|
1575 * |
|
1576 */ |
|
1577 TInt CMMFDevSoundSvrImp::SetDeviceRecordLevel(TInt aGain) |
|
1578 { |
|
1579 TInt error = KErrNone; |
|
1580 if (iRecordCustomInterface) |
|
1581 iRecordCustomInterface->SetGain(aGain); |
|
1582 else error = KErrNotReady; |
|
1583 return error; |
|
1584 |
|
1585 } |
|
1586 |
|
1587 |
|
1588 /** |
|
1589 * |
|
1590 * MMMFHwDeviceObserver mixin implementation. |
|
1591 * |
|
1592 * The CMMFHwDevice implementation object calls this method during decoding |
|
1593 * (playing), when it needs the encoded data in the buffer |
|
1594 * aHwDataBuffer. |
|
1595 * |
|
1596 * @return "TInt" |
|
1597 * Error code. KErrNone if success. |
|
1598 * |
|
1599 */ |
|
1600 TInt CMMFDevSoundSvrImp::FillThisHwBuffer(CMMFBuffer& aHwDataBuffer) |
|
1601 { |
|
1602 TInt err = KErrNone; |
|
1603 // Keep a reference to this Hw data Buffer. We need to send the |
|
1604 // reference back to HwDevice implementation |
|
1605 iHwDeviceBuffer = static_cast<CMMFDataBuffer*> (&aHwDataBuffer); |
|
1606 // Set the request length, From HwDevice this comes with buffer |
|
1607 // length. |
|
1608 TInt len = iHwDeviceBuffer->Data().MaxLength(); |
|
1609 // Ignore error. since buffer size = Buffer Length |
|
1610 TRAP(err, iHwDeviceBuffer->SetRequestSizeL(len)); |
|
1611 |
|
1612 if (iMode== EMMFDevSoundStatePlaying) // Get Data from Observer |
|
1613 { |
|
1614 if (iLastBufferReceived) |
|
1615 { |
|
1616 iHwDeviceBuffer->Data().SetLength(0); |
|
1617 // Pass the buffer to the he device |
|
1618 err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); |
|
1619 } |
|
1620 else |
|
1621 // Pass the buffer to the observer |
|
1622 iDevSoundObserver->BufferToBeFilled(&aHwDataBuffer); |
|
1623 } |
|
1624 else if (iMode == EMMFDevSoundStateTonePlaying) |
|
1625 { |
|
1626 // Hw device will call this method right after its Start was called. |
|
1627 // When it calls this for the first time it hasn't played one single |
|
1628 // buffer yet so check that. |
|
1629 // In this case there's no need to set the active buffer as it's already |
|
1630 // waiting to be played. |
|
1631 if (!iFirstCallFromHwDevice) |
|
1632 SetActiveToneBuffer(); |
|
1633 |
|
1634 // If there is no data in the active buffer, tone play is finished. |
|
1635 // DevSound just have to wait for completion event from audio device. |
|
1636 if (iActiveToneBuffer->Data().Length() > 0) |
|
1637 { |
|
1638 TInt tonelen = iActiveToneBuffer->Data().Length(); |
|
1639 |
|
1640 // don't enter more data than can be handled by the receiving buffer |
|
1641 if (len >= tonelen) len = tonelen; |
|
1642 |
|
1643 // Copy data from tone buffer to hw device buffer |
|
1644 Mem::Copy((TAny*)(iHwDeviceBuffer->Data().Ptr()), (TAny*)(iActiveToneBuffer->Data().Ptr()), len); |
|
1645 |
|
1646 iHwDeviceBuffer->Data().SetLength(len); |
|
1647 // Play data and try to generate next data block |
|
1648 err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); |
|
1649 if (err != KErrNone) |
|
1650 return err; |
|
1651 // Check again whether this is the first call from Hw device. |
|
1652 // FillFreeToneBuffer assumes the iActiveToneBuffer has already |
|
1653 // been played. |
|
1654 if (!iFirstCallFromHwDevice) |
|
1655 err = FillFreeToneBuffer(); |
|
1656 else |
|
1657 iFirstCallFromHwDevice = EFalse; // Reset flag |
|
1658 |
|
1659 } |
|
1660 else if (iFirstCallFromHwDevice) |
|
1661 {//we have no data in the tone buffer and thus have no |
|
1662 //outstanding requests to play |
|
1663 err = KErrUnderflow; //simulate underrun |
|
1664 } |
|
1665 else |
|
1666 { |
|
1667 iHwDeviceBuffer->Data().SetLength(0); |
|
1668 iHwDeviceBuffer->SetLastBuffer(ETrue); |
|
1669 // Send an empty last buffer to HwDevice to get a play completion event with KErrUnderflow |
|
1670 err = iCMMFHwDevice->ThisHwBufferFilled(*iHwDeviceBuffer); |
|
1671 } |
|
1672 |
|
1673 // If there was an error filling the buffer could be corrupt data |
|
1674 // notify the client and stop playing.Set err to KErrNone. |
|
1675 if (err != KErrNone) |
|
1676 { |
|
1677 Error(err);//Updates Bytes played informs client |
|
1678 err = KErrNone; |
|
1679 iCMMFHwDevice->Stop();//unloads sound device |
|
1680 } |
|
1681 } |
|
1682 else |
|
1683 { |
|
1684 err = KErrGeneral; |
|
1685 Error(err); |
|
1686 iCMMFHwDevice->Stop();//unloads sound device |
|
1687 |
|
1688 } |
|
1689 return err; |
|
1690 } |
|
1691 |
|
1692 |
|
1693 /** |
|
1694 * |
|
1695 * MMMFHwDeviceObserver mixin implementation. |
|
1696 * |
|
1697 * The CMMFHwDevice implementation object calls this method during encoding |
|
1698 * (recording), when it fills the buffer aHwDataBuffer with |
|
1699 * encoded data. |
|
1700 * |
|
1701 * @return "TInt" |
|
1702 * Error code. KErrNone if success. |
|
1703 * |
|
1704 */ |
|
1705 TInt CMMFDevSoundSvrImp::EmptyThisHwBuffer(CMMFBuffer& aHwDataBuffer) |
|
1706 { |
|
1707 TInt err = KErrNone; |
|
1708 if(iMode== EMMFDevSoundStateRecording) |
|
1709 { |
|
1710 // Keep a reference to this Hw data Buffer. We need to send the |
|
1711 // reference back to HwDevice implementation |
|
1712 iHwDeviceBuffer = static_cast<CMMFDataBuffer*>(&aHwDataBuffer); |
|
1713 |
|
1714 // Set the request length, From HwDevice this comes with buffer |
|
1715 // length. MMF will use RequestSize attribute of the buffer. |
|
1716 // We can avoid this by setting in HwDevice implemenation |
|
1717 TInt len = iHwDeviceBuffer->Data().Length(); |
|
1718 TRAP(err, iHwDeviceBuffer->SetRequestSizeL(len)); |
|
1719 |
|
1720 // if we're pausing (i.e. flushing) set the last buffer flag |
|
1721 // when we get an empty buffer from the logical driver |
|
1722 if(iPaused && iHwDeviceBuffer->Data().Length() == 0) |
|
1723 { |
|
1724 iPaused = EFalse; |
|
1725 |
|
1726 iHwDeviceBuffer->SetLastBuffer(ETrue); |
|
1727 |
|
1728 iDevSoundEventHandler->CancelReceiveEvents(); |
|
1729 |
|
1730 } |
|
1731 |
|
1732 // Send Data from Observer |
|
1733 iDevSoundObserver->BufferToBeEmptied(iHwDeviceBuffer); |
|
1734 } |
|
1735 else |
|
1736 { |
|
1737 err = KErrGeneral; |
|
1738 Error(err); |
|
1739 iCMMFHwDevice->Stop();//unloads sound device |
|
1740 |
|
1741 } |
|
1742 |
|
1743 return err; |
|
1744 } |
|
1745 |
|
1746 |
|
1747 /** |
|
1748 * |
|
1749 * MMMFHwDeviceObserver mixin implementation. |
|
1750 * |
|
1751 * The CMMFHwDevice implementation object calls this method when a message from |
|
1752 * the hardware device implementation is received. |
|
1753 * |
|
1754 * @return "TInt" |
|
1755 * Error code. KErrNone if success. |
|
1756 * |
|
1757 */ |
|
1758 TInt CMMFDevSoundSvrImp::MsgFromHwDevice(TUid aMessageType, const TDesC8& /*aMsg*/) |
|
1759 { |
|
1760 TInt result = KErrNotSupported; |
|
1761 if (aMessageType.iUid == KMmfHwDeviceObserverUpdateBytesPlayed) |
|
1762 {//this is used by sw codec wrapper to request a bytes played update |
|
1763 //bytes played won't be updated in Stopped() or Error() on sw cdoec wrapper |
|
1764 //as the sound device is closed. Non swCodec wrapper Hw device plugins |
|
1765 //can get there bytes updated on Stopped() and/or Error() |
|
1766 UpdateBytesPlayed(); |
|
1767 result = KErrNone; |
|
1768 } |
|
1769 return result; |
|
1770 } |
|
1771 |
|
1772 /** |
|
1773 * |
|
1774 * MMMFHwDeviceObserver mixin implementation. |
|
1775 * |
|
1776 * The CMMFHwDevice implementation object calls this method when the current |
|
1777 * encode or decode task is finished or stopped. The policy state is updated |
|
1778 * |
|
1779 */ |
|
1780 void CMMFDevSoundSvrImp::Stopped() |
|
1781 { |
|
1782 //for swcodec wrap hw devices bytes played updated in MsgFromHwDevice |
|
1783 //but non Swcodec wrappers hw devices may do it differently |
|
1784 //also don't know if non Swcodec wrap hw device will call Stopped or Error first |
|
1785 UpdateBytesPlayed(); |
|
1786 |
|
1787 iLastBufferReceived = EFalse; |
|
1788 UpdatePolicyState(EMMFStateCompleted); |
|
1789 } |
|
1790 |
|
1791 /** |
|
1792 * MMMFHwDeviceObserver mixin implementation |
|
1793 * Processes error from hw device |
|
1794 */ |
|
1795 void CMMFDevSoundSvrImp::Error(TInt aError) |
|
1796 { |
|
1797 if (iMode== EMMFDevSoundStatePlaying) |
|
1798 { |
|
1799 //for swcodec wrap hw devices bytes played updated in MsgFromHwDevice |
|
1800 //but non Swcodec wrappers hw devices may do it differently |
|
1801 //also don't know if non Swcodec wrap hw device will call Stopped or Error first |
|
1802 UpdateBytesPlayed(); |
|
1803 |
|
1804 iDevSoundObserver->PlayError(aError); |
|
1805 UpdatePolicyState(EMMFStateStopped); |
|
1806 } |
|
1807 else if (iMode== EMMFDevSoundStateRecording) |
|
1808 { |
|
1809 iDevSoundObserver->RecordError(aError); |
|
1810 UpdatePolicyState(EMMFStateStopped); |
|
1811 } |
|
1812 else if (iMode== EMMFDevSoundStateTonePlaying) |
|
1813 { |
|
1814 iDevSoundObserver->ToneFinished(aError); |
|
1815 UpdatePolicyState(EMMFStateStopped); |
|
1816 } |
|
1817 //else can't handle error |
|
1818 } |
|
1819 |
|
1820 |
|
1821 /******************************************************************************** |
|
1822 * Non Exported public functions ends here * |
|
1823 ********************************************************************************/ |
|
1824 |
|
1825 |
|
1826 /******************************************************************************** |
|
1827 * Private functions begins here * |
|
1828 ********************************************************************************/ |
|
1829 |
|
1830 TInt CMMFDevSoundSvrImp::InitializeFormat(RMdaDevSound::TSoundFormatsSupportedBuf& aSupportedFormat, |
|
1831 RMdaDevSound::TCurrentSoundFormatBuf& aFormat) |
|
1832 { |
|
1833 // Choose an encoding |
|
1834 TUint32 enc = aSupportedFormat().iEncodings; |
|
1835 // Always defaults to this |
|
1836 if (enc & RMdaDevSound::EMdaSoundEncoding16BitPCM) |
|
1837 aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; |
|
1838 else if (enc & RMdaDevSound::EMdaSoundEncoding8BitALaw) |
|
1839 aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitALaw; |
|
1840 else if (enc & RMdaDevSound::EMdaSoundEncoding8BitMuLaw) |
|
1841 aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitMuLaw; |
|
1842 else if (enc & RMdaDevSound::EMdaSoundEncoding8BitPCM) |
|
1843 aFormat().iEncoding = RMdaDevSound::EMdaSoundEncoding8BitPCM; |
|
1844 |
|
1845 // default to Monophonic playback: |
|
1846 aFormat().iChannels=1; |
|
1847 |
|
1848 // Store the device capabilities (WINS supports from 8000 Hz to 44100 Hz) |
|
1849 if ((aSupportedFormat().iMinRate <= 8000) && (8000 <= aSupportedFormat().iMaxRate)) |
|
1850 iDeviceCapabilities.iRate = EMMFSampleRate8000Hz; |
|
1851 if ((aSupportedFormat().iMinRate <= 11025) && (11025 <= aSupportedFormat().iMaxRate)) |
|
1852 iDeviceCapabilities.iRate |= EMMFSampleRate11025Hz; |
|
1853 if ((aSupportedFormat().iMinRate <= 12000) && (12000 <= aSupportedFormat().iMaxRate)) |
|
1854 iDeviceCapabilities.iRate |= EMMFSampleRate12000Hz; |
|
1855 if ((aSupportedFormat().iMinRate <= 16000) && (16000 <= aSupportedFormat().iMaxRate)) |
|
1856 iDeviceCapabilities.iRate |= EMMFSampleRate16000Hz; |
|
1857 if ((aSupportedFormat().iMinRate <= 22050) && (22050 <= aSupportedFormat().iMaxRate)) |
|
1858 iDeviceCapabilities.iRate |= EMMFSampleRate22050Hz; |
|
1859 if ((aSupportedFormat().iMinRate <= 24000) && (24000 <= aSupportedFormat().iMaxRate)) |
|
1860 iDeviceCapabilities.iRate |= EMMFSampleRate24000Hz; |
|
1861 if ((aSupportedFormat().iMinRate <= 32000) && (32000 <= aSupportedFormat().iMaxRate)) |
|
1862 iDeviceCapabilities.iRate |= EMMFSampleRate32000Hz; |
|
1863 if ((aSupportedFormat().iMinRate <= 44100) && (44100 <= aSupportedFormat().iMaxRate)) |
|
1864 iDeviceCapabilities.iRate |= EMMFSampleRate44100Hz; |
|
1865 if ((aSupportedFormat().iMinRate <= 48000) && (48000 <= aSupportedFormat().iMaxRate)) |
|
1866 iDeviceCapabilities.iRate |= EMMFSampleRate48000Hz; |
|
1867 if ((aSupportedFormat().iMinRate <= 64000) && (64000 <= aSupportedFormat().iMaxRate)) |
|
1868 iDeviceCapabilities.iRate |= EMMFSampleRate64000Hz; |
|
1869 if ((aSupportedFormat().iMinRate <= 88200) && (88200 <= aSupportedFormat().iMaxRate)) |
|
1870 iDeviceCapabilities.iRate |= EMMFSampleRate88200Hz; |
|
1871 if ((aSupportedFormat().iMinRate <= 96000) && (96000 <= aSupportedFormat().iMaxRate)) |
|
1872 iDeviceCapabilities.iRate |= EMMFSampleRate96000Hz; |
|
1873 |
|
1874 // Store the encodings supported |
|
1875 iDeviceCapabilities.iEncoding = 0; |
|
1876 if (enc & RMdaDevSound::EMdaSoundEncoding16BitPCM) |
|
1877 iDeviceCapabilities.iEncoding |= EMMFSoundEncoding16BitPCM; |
|
1878 if (enc & RMdaDevSound::EMdaSoundEncoding8BitALaw) |
|
1879 iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitALaw; |
|
1880 if (enc & RMdaDevSound::EMdaSoundEncoding8BitMuLaw) |
|
1881 iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitMuLaw; |
|
1882 if (enc & RMdaDevSound::EMdaSoundEncoding8BitPCM) |
|
1883 iDeviceCapabilities.iEncoding |= EMMFSoundEncoding8BitPCM; |
|
1884 |
|
1885 // Mono and Stereo support |
|
1886 if (aSupportedFormat().iChannels == 2) |
|
1887 iDeviceCapabilities.iChannels = EMMFStereo; |
|
1888 iDeviceCapabilities.iChannels |= EMMFMono; |
|
1889 |
|
1890 iDeviceCapabilities.iBufferSize = aSupportedFormat().iMaxBufferSize; |
|
1891 // Default |
|
1892 iDeviceConfig.iRate = EMMFSampleRate8000Hz; |
|
1893 iDeviceConfig.iEncoding = EMMFSoundEncoding16BitPCM; |
|
1894 iDeviceConfig.iChannels = EMMFMono; |
|
1895 |
|
1896 return KErrNone; |
|
1897 } |
|
1898 |
|
1899 /* |
|
1900 * |
|
1901 * Makes request to Policy Server (asynchronous call) |
|
1902 * |
|
1903 */ |
|
1904 void CMMFDevSoundSvrImp::RequestPolicy() |
|
1905 { |
|
1906 iDevSoundEventHandler->CancelReceiveEvents(); |
|
1907 iDevSoundEventHandler->ReceiveEvents(); |
|
1908 iAudioPolicyPrioritySettings.iCapabilities = iParent.CheckClientCapabilities(); |
|
1909 iAudioPolicyProxy->MakeRequest(iAudioPolicyPrioritySettings); |
|
1910 } |
|
1911 |
|
1912 /* |
|
1913 * |
|
1914 * Creates buffer and begin playback using the specified tone generator. |
|
1915 * |
|
1916 */ |
|
1917 void CMMFDevSoundSvrImp::DoPlayL() |
|
1918 { |
|
1919 // Delete any buffer from previous call and try to create maximum buffer |
|
1920 // size. Double Buffer the Tone data. |
|
1921 if (iToneBuffer1) |
|
1922 { |
|
1923 delete iToneBuffer1; |
|
1924 iToneBuffer1 = NULL; |
|
1925 } |
|
1926 //note the tone buffer needs to be the same as the pcm16->pcm16 'null' |
|
1927 //hw device plugin |
|
1928 // Buffer size = (SampleRate * BytesPerSample * Channels) / 4 |
|
1929 TInt useBufferOfSize = ((SamplingFrequency() * 2 * NumberOfChannels())/KDevSoundFramesPerSecond + (KDevSoundDeltaFrameSize-1)) &~ (KDevSoundDeltaFrameSize-1); |
|
1930 //clamp buffer to desired limits |
|
1931 if(useBufferOfSize < KDevSoundMinFrameSize) |
|
1932 useBufferOfSize = KDevSoundMinFrameSize; |
|
1933 else if(useBufferOfSize > KDevSoundMaxFrameSize) |
|
1934 useBufferOfSize = KDevSoundMaxFrameSize; |
|
1935 |
|
1936 //clamp buffer to limits of hardware |
|
1937 if(useBufferOfSize < Max(iPlayFormatsSupported().iMinBufferSize, iRecordFormatsSupported().iMinBufferSize)) |
|
1938 useBufferOfSize = Max(iPlayFormatsSupported().iMinBufferSize, iRecordFormatsSupported().iMinBufferSize); |
|
1939 else if(useBufferOfSize > Min(iPlayFormatsSupported().iMaxBufferSize, iRecordFormatsSupported().iMaxBufferSize)) |
|
1940 useBufferOfSize = Min(iPlayFormatsSupported().iMaxBufferSize, iRecordFormatsSupported().iMaxBufferSize); |
|
1941 |
|
1942 iToneBuffer1 = CMMFDataBuffer::NewL(useBufferOfSize); |
|
1943 User::LeaveIfError(iCurrentGenerator->FillBuffer(iToneBuffer1->Data())); |
|
1944 |
|
1945 if (iToneBuffer2) |
|
1946 { |
|
1947 delete iToneBuffer2; |
|
1948 iToneBuffer2 = NULL; |
|
1949 } |
|
1950 iToneBuffer2 = CMMFDataBuffer::NewL(useBufferOfSize); |
|
1951 User::LeaveIfError(iCurrentGenerator->FillBuffer(iToneBuffer2->Data())); |
|
1952 |
|
1953 // Assign active buffer |
|
1954 iActiveToneBuffer = iToneBuffer1; |
|
1955 |
|
1956 // Hw device hasn't played anything yet so don't change |
|
1957 // active buffer. This is checked in FillThisHwBuffer. |
|
1958 iFirstCallFromHwDevice = ETrue; |
|
1959 |
|
1960 // Start HwDevice to play data |
|
1961 User::LeaveIfError(iCMMFHwDevice->Start(EDevDecode, EDevOutFlow)); |
|
1962 |
|
1963 } |
|
1964 |
|
1965 /* |
|
1966 * |
|
1967 * This method assigns the other buffer as active buffer. The tone audio |
|
1968 * generator should fill data in the other buffer by now. |
|
1969 * |
|
1970 */ |
|
1971 void CMMFDevSoundSvrImp::SetActiveToneBuffer() |
|
1972 { |
|
1973 if (iActiveToneBuffer == iToneBuffer1) |
|
1974 iActiveToneBuffer = iToneBuffer2; |
|
1975 else if (iActiveToneBuffer == iToneBuffer2) |
|
1976 iActiveToneBuffer = iToneBuffer1; |
|
1977 } |
|
1978 |
|
1979 /* |
|
1980 * |
|
1981 * This method fills data into the free buffer. |
|
1982 * |
|
1983 * @return "TInt" |
|
1984 * Error code. KErrNone if success. |
|
1985 * |
|
1986 */ |
|
1987 TInt CMMFDevSoundSvrImp::FillFreeToneBuffer() |
|
1988 { |
|
1989 TInt err(KErrNone); |
|
1990 if (iActiveToneBuffer == iToneBuffer1) |
|
1991 err = iCurrentGenerator->FillBuffer(iToneBuffer2->Data()); |
|
1992 else if (iActiveToneBuffer == iToneBuffer2) |
|
1993 err = iCurrentGenerator->FillBuffer(iToneBuffer1->Data()); |
|
1994 return err; |
|
1995 } |
|
1996 |
|
1997 /* |
|
1998 * |
|
1999 * Updates the policy state based on Audio policy settings of this devsound instance |
|
2000 * |
|
2001 */ |
|
2002 TInt CMMFDevSoundSvrImp::UpdatePolicyState(TMMFAudioPolicyState aNewState) |
|
2003 { |
|
2004 iAudioPolicyPrioritySettings.iState = aNewState; |
|
2005 TInt error = iAudioPolicyProxy->UpdateState(iAudioPolicyPrioritySettings); |
|
2006 if ((error == KErrNone) && (aNewState == EMMFStateStopped)) |
|
2007 { |
|
2008 iHasPolicy = EFalse; |
|
2009 } |
|
2010 |
|
2011 return error; |
|
2012 } |
|
2013 |
|
2014 /* |
|
2015 * |
|
2016 * Initializes audio device node by setting volume, and sampling rate. |
|
2017 * |
|
2018 * @return "TInt" |
|
2019 * Error Code. KErrNone if success. |
|
2020 * |
|
2021 */ |
|
2022 TInt CMMFDevSoundSvrImp::InitTask() |
|
2023 { |
|
2024 // No Implementation |
|
2025 return KErrNone; |
|
2026 } |
|
2027 |
|
2028 |
|
2029 |
|
2030 /* |
|
2031 * |
|
2032 * Returns an integer representing Sampling Frequency the device is currently |
|
2033 * configured to. |
|
2034 * |
|
2035 * @return "TInt" |
|
2036 * Sampling Frequency. |
|
2037 * |
|
2038 */ |
|
2039 TInt CMMFDevSoundSvrImp::SamplingFrequency() |
|
2040 { |
|
2041 if(iDeviceConfig.iRate == EMMFSampleRate8000Hz) |
|
2042 return 8000; |
|
2043 else if(iDeviceConfig.iRate == EMMFSampleRate11025Hz) |
|
2044 return 11025; |
|
2045 else if(iDeviceConfig.iRate == EMMFSampleRate12000Hz) |
|
2046 return 12000; |
|
2047 else if(iDeviceConfig.iRate == EMMFSampleRate16000Hz) |
|
2048 return 16000; |
|
2049 else if(iDeviceConfig.iRate == EMMFSampleRate22050Hz) |
|
2050 return 22050; |
|
2051 else if(iDeviceConfig.iRate == EMMFSampleRate24000Hz) |
|
2052 return 24000; |
|
2053 else if(iDeviceConfig.iRate == EMMFSampleRate32000Hz) |
|
2054 return 32000; |
|
2055 else if(iDeviceConfig.iRate == EMMFSampleRate44100Hz) |
|
2056 return 44100; |
|
2057 else if(iDeviceConfig.iRate == EMMFSampleRate48000Hz) |
|
2058 return 48000; |
|
2059 else if(iDeviceConfig.iRate == EMMFSampleRate88200Hz) |
|
2060 return 88200; |
|
2061 else if(iDeviceConfig.iRate == EMMFSampleRate96000Hz) |
|
2062 return 96000; |
|
2063 else |
|
2064 return 8000; //default |
|
2065 } |
|
2066 |
|
2067 /* |
|
2068 * |
|
2069 * Returns an integer representing number of channels the device is currently |
|
2070 * configured to. |
|
2071 * |
|
2072 * @return "TInt" |
|
2073 * Number of audio channels 1 if mono, 2 if stereo. |
|
2074 * |
|
2075 */ |
|
2076 TInt CMMFDevSoundSvrImp::NumberOfChannels() |
|
2077 { |
|
2078 if(iDeviceConfig.iChannels == EMMFMono) |
|
2079 return 1; |
|
2080 else |
|
2081 return 2; |
|
2082 } |
|
2083 |
|
2084 /* |
|
2085 * |
|
2086 * Returns an integer representing number of bytes in each audio sample |
|
2087 * |
|
2088 * |
|
2089 * @return "TInt" |
|
2090 * Number of of bytes in each audio sample. |
|
2091 * |
|
2092 */ |
|
2093 TInt CMMFDevSoundSvrImp::BytesPerAudioSample() |
|
2094 { |
|
2095 TInt bytes=1; |
|
2096 switch (iDeviceConfig.iEncoding) |
|
2097 { |
|
2098 case EMMFSoundEncoding8BitPCM: |
|
2099 case EMMFSoundEncoding8BitALaw: |
|
2100 case EMMFSoundEncoding8BitMuLaw: |
|
2101 { |
|
2102 bytes=1; |
|
2103 } |
|
2104 break; |
|
2105 case EMMFSoundEncoding16BitPCM: |
|
2106 { |
|
2107 bytes=2; |
|
2108 } |
|
2109 break; |
|
2110 } |
|
2111 return bytes; |
|
2112 } |
|
2113 |
|
2114 |
|
2115 /******************************************************************************** |
|
2116 * Private functions ends here * |
|
2117 ********************************************************************************/ |
|
2118 |
|
2119 |
|
2120 // CustomCommand* implementation: |
|
2121 // The following come through from the parent object intact - currently it seems |
|
2122 // easier to pass this through with an RMessage, as the result parameter (at least) |
|
2123 // is easier to deal with that way. This might change in the future. |
|
2124 // [TODO - if we extended this to CMMFHwDevice, it might be easier to use some sort |
|
2125 // of TMMFCustomCommandParamBlock throughout, which as well as the uid, in params etc |
|
2126 // by value, also provided a virtual(?) function to set output param. Could then |
|
2127 // use in both plat sec and original code |
|
2128 |
|
2129 void CMMFDevSoundSvrImp::DoSyncCustomCommandL(const RMmfIpcMessage& aMessage) |
|
2130 { |
|
2131 TInt command = aMessage.Int0(); |
|
2132 |
|
2133 // we don't support any commands at the momment |
|
2134 User::Leave(KErrNotSupported); |
|
2135 } |
|
2136 |
|
2137 void CMMFDevSoundSvrImp::DoSyncCustomCommandResultL(const RMmfIpcMessage& aMessage) |
|
2138 { |
|
2139 TInt command = aMessage.Int0(); |
|
2140 |
|
2141 // we don't support any commands at the momment |
|
2142 User::Leave(KErrNotSupported); |
|
2143 } |
|
2144 |
|
2145 void CMMFDevSoundSvrImp::DoAsyncCustomCommandL(const RMmfIpcMessage& aMessage) |
|
2146 { |
|
2147 TInt command = aMessage.Int0(); |
|
2148 |
|
2149 // we don't support any commands at the momment |
|
2150 User::Leave(KErrNotSupported); // this will still complete for an async message |
|
2151 } |
|
2152 |
|
2153 void CMMFDevSoundSvrImp::DoAsyncCustomCommandResultL(const RMmfIpcMessage& aMessage) |
|
2154 { |
|
2155 TInt command = aMessage.Int0(); |
|
2156 |
|
2157 // we don't support any commands at the moment |
|
2158 User::Leave(KErrNotSupported); // this will still complete for an async message |
|
2159 } |
|
2160 |