First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include <mmf/plugin/mmfhwdeviceimplementationuids.hrh>
17 #include "SoundDeviceBody.h"
18 #include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh> // KUidRefDevSoundTaskConfig
20 const TInt KMaxMessageQueueItems = 8;
24 * Default Constructor.
26 * No default implementation. CMMFDevSound implements 2-phase construction.
29 CMMFDevSoundClientImp::CMMFDevSoundClientImp()
37 * Deletes all objects and releases all resource owned by this
41 CMMFDevSoundClientImp::~CMMFDevSoundClientImp()
43 // clear the array of custom interfaces
44 for (TInt i = 0; i < iCustomInterfaceArray.Count(); i++)
46 iCustomInterfaceArray[i].iInterface->Release();
48 iCustomInterfaceArray.Reset();
49 iCustomInterfaceArray.Close();
51 // delete the MUX utility
54 if (iMsgQueueHandler && iMsgQueueHandler->IsActive())
56 iMsgQueueHandler->Cancel();
58 delete iMsgQueueHandler;
62 if( iDevSoundProxy != NULL)
64 iDevSoundProxy->Close();
65 delete iDevSoundProxy;
71 * Constructs, and returns a pointer to, a new CMMFDevSound object.
76 CMMFDevSoundClientImp* CMMFDevSoundClientImp::NewL()
78 CMMFDevSoundClientImp* self = new (ELeave) CMMFDevSoundClientImp();
79 CleanupStack::PushL(self);
81 CleanupStack::Pop(self);
87 * 2nd phase constructor - assumes that iParent has already been set up properly.
90 void CMMFDevSoundClientImp::ConstructL()
92 // all these data properties should be NULL, but add ASSERTs to verify
94 ASSERT(iDevSoundProxy==NULL);
95 iDevSoundProxy = new (ELeave) RMMFDevSoundProxy();
97 TInt err = iMsgQueue.CreateGlobal(KNullDesC, KMaxMessageQueueItems); // global, accessible to all that have its handle
98 User::LeaveIfError(err);
99 err = iDevSoundProxy->Open(iMsgQueue);
102 delete iDevSoundProxy;
103 iDevSoundProxy = NULL;
106 User::LeaveIfError(err);
108 // create MUX utility
109 iMuxUtility = CMMFDevSoundCIMuxUtility::NewL(this);
115 * Initializes CMMFDevSound object to play and record PCM16 raw audio data
116 * with sampling rate of 8 KHz.
118 * On completion of Initialization, calls InitializeComplete() on
123 * @param "MDevSoundObserver& aDevSoundObserver"
124 * A reference to DevSound Observer instance.
126 * @param "TMMFState aMode"
127 * Mode for which this object will be used.
130 void CMMFDevSoundClientImp::InitializeL(MDevSoundObserver& aDevSoundObserver, TMMFState aMode)
133 TInt initError = KErrNone;
134 iDevSoundObserver = &aDevSoundObserver;
135 initError = iDevSoundProxy->InitializeL(aMode);
139 User::Leave(initError);
142 if (iMsgQueueHandler)
144 iMsgQueueHandler->Cancel();
145 iMsgQueueHandler->SetObserver(*iDevSoundObserver);
149 iMsgQueueHandler = CMsgQueueHandler::NewL(iDevSoundProxy, *iDevSoundObserver, &iMsgQueue, *this);
152 iMsgQueueHandler->ReceiveEvents();
157 * Configure CMMFDevSound object for the settings in aConfig.
159 * Use this to set sampling rate, Encoding and Mono/Stereo.
161 * @param "TMMFCapabilities& aConfig"
162 * Attribute values to which CMMFDevSound object will be configured to.
164 * As part of defect 20796, the iRecordFormat has been set under the iPlayFormat,
165 * before it was not set at all.
168 void CMMFDevSoundClientImp::SetConfigL(const TMMFCapabilities& aConfig)
170 iDevSoundProxy->SetConfigL(aConfig);
175 * Changes the current playback volume to a specified value.
177 * The volume can be changed before or during playback and is effective
180 * @param "TInt aVolume"
181 * The volume setting. This can be any value from zero to the value
182 * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the
183 * volume is not within this range, the volume is automatically set to
184 * minimum or maximum value based on the value that is being passed.
185 * Setting a zero value mutes the sound. Setting the maximum value
186 * results in the loudest possible sound.
189 void CMMFDevSoundClientImp::SetVolume(TInt aVolume)
191 iDevSoundProxy->SetVolume(aVolume);
196 * Changes the current recording gain to a specified value.
198 * The gain can be changed before or during recording and is effective
201 * @param "TInt aGain"
202 * The volume setting. This can be any value from zero to the value
203 * returned by a call to CMdaAudioPlayerUtility::MaxVolume(). If the
204 * volume is not within this range, the gain is automatically set to
205 * minimum or maximum value based on the value that is being passed.
206 * Setting a zero value mutes the sound. Setting the maximum value
207 * results in the loudest possible sound.
210 void CMMFDevSoundClientImp::SetGain(TInt aGain)
212 iDevSoundProxy->SetGain(aGain);
217 * Sets the speaker balance for playing.
219 * The speaker balance can be changed before or during playback and is
220 * effective immediately.
222 * @param "TInt& aLeftPercentage"
223 * On return contains left speaker volume perecentage. This can be any
224 * value from zero to 100. Setting a zero value mutes the sound on left
227 * @param "TInt& aRightPercentage"
228 * On return contains right speaker volume perecentage. This can be any
229 * value from zero to 100. Setting a zero value mutes the sound on
233 void CMMFDevSoundClientImp::SetPlayBalanceL(TInt aLeftPercentage, TInt aRightPercentage)
235 iDevSoundProxy->SetPlayBalanceL(aLeftPercentage, aRightPercentage);
240 * Sets the microphone gain balance for recording.
242 * The microphone gain balance can be changed before or during recording and
243 * is effective immediately.
245 * @param "TInt aLeftPercentage"
246 * Left microphone gain precentage. This can be any value from zero to
247 * 100. Setting a zero value mutes the gain on left microphone.
249 * @param "TInt aRightPercentage"
250 * Right microphone gain precentage. This can be any value from zero to
251 * 100. Setting a zero value mutes the gain on right microphone.
254 void CMMFDevSoundClientImp::SetRecordBalanceL(TInt aLeftPercentage, TInt aRightPercentage)
256 iDevSoundProxy->SetRecordBalanceL(aLeftPercentage, aRightPercentage);
261 * Initializes audio device and start play process. This method queries and
262 * acquires the audio policy before initializing audio device. If there was an
263 * error during policy initialization, PlayError() method will be called on
264 * the observer with error code KErrAccessDenied, otherwise BufferToBeFilled()
265 * method will be called with a buffer reference. After reading data into the
266 * buffer reference passed, the client should call PlayData() to play data.
268 * The amount of data that can be played is specified in
269 * CMMFBuffer::RequestSize(). Any data that is read into buffer beyond this
270 * size will be ignored.
275 void CMMFDevSoundClientImp::PlayInitL()
277 if (!iDevSoundObserver)
278 User::Leave(KErrNotReady);
279 iDevSoundProxy->PlayInitL();
284 * Initializes audio device and start record process. This method queries and
285 * acquires the audio policy before initializing audio device. If there was an
286 * error during policy initialization, RecordError() method will be called on
287 * the observer with error code KErrAccessDenied, otherwise BufferToBeEmptied()
288 * method will be called with a buffer reference. This buffer contains recorded
289 * or encoded data. After processing data in the buffer reference passed, the
290 * client should call RecordData() to continue recording process.
292 * The amount of data that is available is specified in
293 * CMMFBuffer::RequestSize().
298 void CMMFDevSoundClientImp::RecordInitL()
301 if (!iDevSoundObserver)
302 User::Leave(KErrNotReady);
303 iDevSoundProxy->RecordInitL();
308 * Plays data in the buffer at the current volume. The client should fill
309 * the buffer with audio data before calling this method. The Observer gets
310 * reference to buffer along with callback BufferToBeFilled(). When playing of
311 * the audio sample is complete, successfully or otherwise, the method
312 * PlayError() on observer is called.
315 void CMMFDevSoundClientImp::PlayData()
317 ASSERT(iDevSoundObserver);
318 iDevSoundProxy->PlayData();
323 * Stops the ongoing operation (Play, Record, TonePlay, Convert)
326 void CMMFDevSoundClientImp::Stop()
328 iDevSoundProxy->Stop();
333 * Temporarily Stops the ongoing operation (Play, Record, TonePlay, Convert)
336 void CMMFDevSoundClientImp::Pause()
338 iDevSoundProxy->Pause();
343 * Returns the sample recorded so far.
346 * Returns the samples recorded.
349 TInt CMMFDevSoundClientImp::SamplesRecorded()
351 return iDevSoundProxy->SamplesRecorded();
356 * Returns the sample played so far.
359 * Returns the samples recorded.
362 TInt CMMFDevSoundClientImp::SamplesPlayed()
364 return iDevSoundProxy->SamplesPlayed();
370 * Initializes audio device and start playing tone. Tone is played with
371 * frequency and for duration specified.
375 * @param "TInt aFrequency"
376 * Frequency at with the tone will be played.
378 * @param "TTimeIntervalMicroSeconds& aDuration"
379 * The period over which the tone will be played. A zero value causes
380 * the no tone to be played (Verify this with test app).
383 void CMMFDevSoundClientImp::PlayToneL(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
385 iDevSoundProxy->PlayToneL(aFrequency, aDuration);
389 * Initializes audio device and start playing a dual tone.
390 * The tone consists of two sine waves of different frequencies summed together
391 * Dual Tone is played with specified frequencies and for specified duration.
393 * @param "aFrequencyOne"
394 * First frequency of dual tone
396 * @param "aFrequencyTwo"
397 * Second frequency of dual tone
400 * The period over which the tone will be played. A zero value causes
401 * the no tone to be played (Verify this with test app).
403 void CMMFDevSoundClientImp::PlayDualToneL(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
405 iDevSoundProxy->PlayDualToneL(aFrequencyOne, aFrequencyTwo, aDuration);
410 * Initializes audio device and start playing DTMF string aDTMFString.
414 * @param "TDesC& aDTMFString"
415 * DTMF sequence in a descriptor.
418 void CMMFDevSoundClientImp::PlayDTMFStringL(const TDesC& aDTMFString)
420 if (!iDevSoundObserver)
421 User::Leave(KErrNotReady);
423 iDevSoundProxy->PlayDTMFStringL(aDTMFString);
428 * Initializes audio device and start playing tone sequence.
432 * @param "TDesC8& aData"
433 * Tone sequence in a descriptor.
436 void CMMFDevSoundClientImp::PlayToneSequenceL(const TDesC8& aData)
438 if (!iDevSoundObserver)
439 User::Leave(KErrNotReady);
441 iDevSoundProxy->PlayToneSequenceL(aData);
446 * Initializes audio device and start playing the specified pre-defined tone
451 * @param "TInt aSequenceNumber"
452 * The index identifying the specific pre-defined tone sequence. Index
453 * values are relative to zero.
454 * This can be any value from zero to the value returned by a call to
455 * CMdaAudioPlayerUtility::FixedSequenceCount() - 1.
456 * The function raises a panic if sequence number is not within this
460 void CMMFDevSoundClientImp::PlayFixedSequenceL(TInt aSequenceNumber)
462 if (!iDevSoundObserver)
463 User::Leave(KErrNotReady);
465 iDevSoundProxy->PlayFixedSequenceL(aSequenceNumber);
470 * Defines the duration of tone on, tone off and tone pause to be used during the
471 * DTMF tone playback operation.
473 * Supported only during tone playing.
475 * @param "TTimeIntervalMicroSeconds32& aToneOnLength"
476 * The period over which the tone will be played. If this is set to
477 * zero, then the tone is not played.
479 * @param "TTimeIntervalMicroSeconds32& aToneOffLength"
480 * The period over which the no tone will be played.
482 * @param "TTimeIntervalMicroSeconds32& aPauseLength"
483 * The period over which the tone playing will be paused.
486 void CMMFDevSoundClientImp::SetDTMFLengths(TTimeIntervalMicroSeconds32& aToneOnLength,
487 TTimeIntervalMicroSeconds32& aToneOffLength,
488 TTimeIntervalMicroSeconds32& aPauseLength)
490 iDevSoundProxy->SetDTMFLengths(aToneOnLength, aToneOffLength, aPauseLength);
495 * Defines the period over which the volume level is to rise smoothly from
496 * nothing to the normal volume level.
498 * @param "TTimeIntervalMicroSeconds& aRampDuration"
499 * The period over which the volume is to rise. A zero value causes
500 * the tone sample to be played at the normal level for the full
501 * duration of the playback. A value, which is longer than the duration
502 * of the tone sample, that the sample never reaches its normal
507 void CMMFDevSoundClientImp::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
509 iDevSoundProxy->SetVolumeRamp(aRampDuration);
516 void CMMFDevSoundClientImp::GetSupportedInputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& aPrioritySettings) const
518 iDevSoundProxy->GetSupportedInputDataTypesL(aSupportedDataTypes, aPrioritySettings);
524 void CMMFDevSoundClientImp::GetSupportedOutputDataTypesL(RArray<TFourCC>& aSupportedDataTypes, const TMMFPrioritySettings& aPrioritySettings) const
526 iDevSoundProxy->GetSupportedOutputDataTypesL(aSupportedDataTypes, aPrioritySettings);
532 TInt CMMFDevSoundClientImp::SetClientThreadInfo(TThreadId aTid)
534 return iDevSoundProxy->SetClientThreadInfo(aTid);
538 TInt CMMFDevSoundClientImp::RegisterAsClient(TUid aEventType, const TDesC8& aNotificationRegistrationData)
540 return iDevSoundProxy->RegisterAsClient(aEventType,aNotificationRegistrationData);
543 TInt CMMFDevSoundClientImp::CancelRegisterAsClient(TUid aEventType)
545 return iDevSoundProxy->CancelRegisterAsClient(aEventType);
548 TInt CMMFDevSoundClientImp::GetResourceNotificationData(TUid aEventType,TDes8& aNotificationData)
550 return iDevSoundProxy->GetResourceNotificationData(aEventType,aNotificationData);
553 TInt CMMFDevSoundClientImp::WillResumePlay()
555 return iDevSoundProxy->WillResumePlay();
558 TInt CMMFDevSoundClientImp::EmptyBuffers()
560 return iDevSoundProxy->EmptyBuffers();
563 TInt CMMFDevSoundClientImp::GetTimePlayed(TTimeIntervalMicroSeconds& aTime)
565 return iDevSoundProxy->GetTimePlayed(aTime);
569 * Returns a given Custom Interface on the DevSound based on the UID
570 * If this is not recognised then the custominterface is created by
571 * a pair of ECOM plugins.
574 * @param "TUid aInterfaceId"
575 * The UID of the required Custom Interface
576 * @return a pointer to the custom interface
579 TAny* CMMFDevSoundClientImp::CustomInterface(TUid aInterfaceId)
581 // check if this UID refers to auto/pause/resume
582 if (aInterfaceId == KMmfUidDevSoundAudioResourceCustomInterface)
584 MAutoPauseResumeSupport* result = this;
587 if (aInterfaceId == KMmfUidDevSoundEmptyBuffersCustomInterface)
589 MMMFDevSoundEmptyBuffers* result = this;
592 if (aInterfaceId == KMmfUidDevSoundAudioClientThreadInfoCustomInterface)
594 MAudioClientThreadInfo* result = this;
598 if (aInterfaceId == KMmfUidDevSoundTimePlayedCustomInterface)
600 MMMFDevSoundTimePlayed* result = this;
604 // we are being asked for a Custom Interface not natively supported
605 // by the DevSound plugin.
607 // first check if we already have resolved a custom interface of this type
608 TInt index = FindCustomInterface(aInterfaceId);
610 MMMFDevSoundCustomInterfaceMuxPlugin* ptr = NULL;
612 // if we found the interface, take a copy of this instead
613 if (index != KNullHandle)
615 // check our index is valid
616 ptr = iCustomInterfaceArray[index-1].iInterface;
619 return ptr->CustomInterface(aInterfaceId);
623 // we may not need this code because this
624 // *should* be impossible to reach
630 // else try and instantiate a plugin tunnelling
631 // pair to support this Custom Interface
632 TRAPD(err, ptr = iMuxUtility->CreateCustomInterfaceMuxL(aInterfaceId));
634 if (ptr && (err == KErrNone))
636 TMMFDevSoundCustomInterfaceData data;
637 data.iInterface = ptr;
638 data.iId = aInterfaceId;
640 // attempt to open remote demux
641 // this will store a handle in the mux plugin if successful
642 // and also return it here - invalid handle = -1
643 data.iHandle = ptr->OpenInterface(aInterfaceId);
645 // if the handle is greater than zero then we know we have
646 // successfully opened the interface
647 if (data.iHandle > KNullHandle)
649 // append this to the current interface list
651 err = iCustomInterfaceArray.Append(data);
654 // return the custom interface on the ptr
655 return ptr->CustomInterface(aInterfaceId);
659 // no memory or other problem so shut down interface
665 // if code gets here then we don't support the interface
666 // so we can pass it onto the DevSound proxy so that we
667 // can attempt to resolve the interface externally
668 return iDevSoundProxy->CustomInterface(aInterfaceId);
671 TInt CMMFDevSoundClientImp::FindCustomInterface(TUid aInterfaceId)
673 TInt index = KNullHandle;
675 for (TInt i = 0; i < iCustomInterfaceArray.Count(); i++)
677 if (iCustomInterfaceArray[i].iId == aInterfaceId)
679 index = i+1; // use index+1 as the handle, so 0 is undefined/not-found
687 void CMMFDevSoundClientImp::CloseCustomInterface(TInt aIndex)
689 for (TInt i = 0; i < iCustomInterfaceArray.Count(); i++)
691 if(iCustomInterfaceArray[i].iHandle == aIndex)
693 iCustomInterfaceArray[i].iInterface->Release();
694 iCustomInterfaceArray.Remove(i);