|
1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Class for producing audio feedback. |
|
15 * Part of: Tactile Feedback. |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 #include <e32debug.h> |
|
21 |
|
22 #include <centralrepository.h> |
|
23 #include <ecom/implementationproxy.h> |
|
24 |
|
25 #include <audiopreference.h> |
|
26 #include <mda/common/audio.h> |
|
27 #include <mdaaudiooutputstream.h> |
|
28 |
|
29 #include "tactilefeedbackprivatecrkeys.h" |
|
30 #include "tactilefeedbacktrace.h" |
|
31 |
|
32 #include "tactileaudioplayer.h" |
|
33 #include "OstTraceDefinitions.h" |
|
34 #ifdef OST_TRACE_COMPILER_IN_USE |
|
35 #include "tactileaudioplayerTraces.h" |
|
36 #endif |
|
37 |
|
38 const TInt KRiffHeaderSize = 44; |
|
39 _LIT8( KRiff, "RIFF" ); |
|
40 _LIT8( KWave, "WAVE" ); |
|
41 _LIT8( KFmt, "fmt " ); |
|
42 _LIT8( KData, "data" ); |
|
43 |
|
44 // --------------------------------------------------------------------------- |
|
45 // Constructor. |
|
46 // --------------------------------------------------------------------------- |
|
47 // |
|
48 CTactileAudioPlayer::CTactileAudioPlayer( CRepository& aRepository ): |
|
49 iRepository( aRepository ) |
|
50 { |
|
51 } |
|
52 |
|
53 // --------------------------------------------------------------------------- |
|
54 // 2nd phase constructor. |
|
55 // --------------------------------------------------------------------------- |
|
56 // |
|
57 void CTactileAudioPlayer::ConstructL() |
|
58 { |
|
59 TRACE("CTactileAudioPlayer::ConstructL()"); |
|
60 |
|
61 ReadSettingsL(); |
|
62 |
|
63 CreateWavPlayerL(); |
|
64 |
|
65 iCenRepNotifier = CCenRepNotifyHandler::NewL( *this, |
|
66 iRepository, |
|
67 CCenRepNotifyHandler::EIntKey, |
|
68 KTactileFeedbackAudioVolume ); |
|
69 iCenRepNotifier->StartListeningL(); |
|
70 |
|
71 TRACE("CTactileAudioPlayer::ConstructL() - end"); |
|
72 } |
|
73 |
|
74 // --------------------------------------------------------------------------- |
|
75 // 2-phased constructor. |
|
76 // --------------------------------------------------------------------------- |
|
77 // |
|
78 CTactileAudioPlayer* CTactileAudioPlayer::NewL( CRepository& aRepository ) |
|
79 { |
|
80 CTactileAudioPlayer* self = |
|
81 new ( ELeave ) CTactileAudioPlayer( aRepository ); |
|
82 CleanupStack::PushL( self ); |
|
83 self->ConstructL( ); |
|
84 CleanupStack::Pop( self ); |
|
85 return self; |
|
86 } |
|
87 |
|
88 // --------------------------------------------------------------------------- |
|
89 // Destructor. |
|
90 // --------------------------------------------------------------------------- |
|
91 // |
|
92 CTactileAudioPlayer::~CTactileAudioPlayer() |
|
93 { |
|
94 if ( iAudioPlayer ) |
|
95 { |
|
96 iAudioPlayer->Stop(); |
|
97 delete iAudioPlayer; |
|
98 } |
|
99 |
|
100 delete iCenRepNotifier; |
|
101 delete iSensitiveSample; |
|
102 delete iBasicSample; |
|
103 delete iSensitiveFileName; |
|
104 delete iBasicFileName; |
|
105 |
|
106 iVolumeLevels.Close(); |
|
107 } |
|
108 |
|
109 |
|
110 // --------------------------------------------------------------------------- |
|
111 // From class CTactilePlayer |
|
112 // |
|
113 // Currently we only select volume level according to logical feedback type |
|
114 // (i.e. the .wav -file cannot be selected separately for each logical |
|
115 // feedback type). |
|
116 // |
|
117 // We don't do anything in case volume level has been set to zero for the |
|
118 // given feedback type (this way e.g. dragging feedback can be disabled |
|
119 // totally if that is wanted). |
|
120 // |
|
121 // Notice that currently the ETouchFeedbackSensitive -feedback is a bit |
|
122 // troublesome: Even though we have our own thread for feedback playing, |
|
123 // it still lags behind when something is dragged on screen. Final solution |
|
124 // may be to configure audio .wav dragging feedback OFF, and use audio |
|
125 // tone for dragging instead. |
|
126 // --------------------------------------------------------------------------- |
|
127 // |
|
128 TInt CTactileAudioPlayer::PlayFeedback( TTouchLogicalFeedback aFeedback ) |
|
129 { |
|
130 TRACE2( "CTactileAudioPlayer::PlayFeedback( %d )", aFeedback ); |
|
131 TInt volumeIndex(0); |
|
132 |
|
133 switch ( aFeedback ) |
|
134 { |
|
135 case ETouchFeedbackBasic: // flow through |
|
136 case ETouchFeedbackBasicButton: // flow through |
|
137 case ETouchFeedbackList: // flow through |
|
138 case ETouchFeedbackBoundaryList: // flow through |
|
139 case ETouchFeedbackSlider: // flow through |
|
140 case ETouchFeedbackEdit: // flow through |
|
141 case ETouchFeedbackSensitiveInput: |
|
142 case ETouchFeedbackLineSelection: // flow through |
|
143 case ETouchFeedbackBlankSelection: // flow through |
|
144 case ETouchFeedbackTextSelection: // flow through |
|
145 case ETouchFeedbackEmptyLineSelection: // flow through |
|
146 case ETouchFeedbackTab: // flow through |
|
147 case ETouchFeedbackPopUp: // flow through |
|
148 case ETouchFeedbackIncreasingPopUp: // flow through |
|
149 case ETouchFeedbackDecreasingPopUp: // flow through |
|
150 case ETouchFeedbackFlick: // flow through |
|
151 case ETouchFeedbackCheckbox: // flow through |
|
152 case ETouchFeedbackCharacterInputButton: |
|
153 case ETouchFeedbackMultiTouchRecognized: |
|
154 volumeIndex = 0; |
|
155 break; |
|
156 case ETouchFeedbackSensitive: // flow through |
|
157 case ETouchFeedbackSensitiveButton: // flow through |
|
158 case ETouchFeedbackSensitiveList: |
|
159 volumeIndex = 1; |
|
160 break; |
|
161 default: |
|
162 // should not be there at all |
|
163 TRACE2( "CTactileAudioPlayer::PlayFeedback - %d is not a feedback type - returning", aFeedback ); |
|
164 break; |
|
165 } |
|
166 |
|
167 |
|
168 if ( volumeIndex <= iVolumeLevels.Count() && |
|
169 iVolumeLevels[volumeIndex] > 0 && |
|
170 iAudioPlayer ) |
|
171 { |
|
172 switch ( iState ) |
|
173 { |
|
174 case ETactileAudioInitialising: |
|
175 // can't play anything yet |
|
176 break; |
|
177 case ETactileAudioPlaying: // fall trough |
|
178 case ETactileAudioReady: |
|
179 OstTrace1( TACTILE_PERFORMANCE, TACTILE_PLAY_AUDIO_FEEDBACK_1, |
|
180 "e_TACTILE_PLAY_AUDIO_FEEDBACK 1 0x%x", aFeedback ); |
|
181 |
|
182 if ( aFeedback == ETouchFeedbackBasic ) |
|
183 { |
|
184 TRAP_IGNORE( iAudioPlayer->WriteL( *iBasicSample ) ); |
|
185 } |
|
186 else |
|
187 { |
|
188 TRAP_IGNORE( iAudioPlayer->WriteL( *iSensitiveSample ) ); |
|
189 } |
|
190 OstTrace1( TACTILE_PERFORMANCE, TACTILE_PLAY_AUDIO_FEEDBACK_0, |
|
191 "e_TACTILE_PLAY_AUDIO_FEEDBACK 0 0x%x", aFeedback ); |
|
192 iState = ETactileAudioPlaying; |
|
193 break; |
|
194 case ETactileAudioError: |
|
195 break; |
|
196 default: |
|
197 // should not be here |
|
198 TRACE("CTactileAudioPlayer::PlayFeedback - error with audio device"); |
|
199 break; |
|
200 |
|
201 } |
|
202 |
|
203 } |
|
204 else |
|
205 { |
|
206 if ( !iAudioPlayer ) |
|
207 { |
|
208 TRACE("CTactileAudioPlayer::PlayFeedback - iAudioPlayer is NULL!"); |
|
209 } |
|
210 else |
|
211 { |
|
212 TRACE("CTactileAudioPlayer::PlayFeedback - volume levels not ok"); |
|
213 } |
|
214 } |
|
215 TRACE2( "CTactileAudioPlayer::PlayFeedback( %d ) - end", aFeedback ); |
|
216 return KErrNone; |
|
217 } |
|
218 |
|
219 // --------------------------------------------------------------------------- |
|
220 // |
|
221 // --------------------------------------------------------------------------- |
|
222 // |
|
223 TInt CTactileAudioPlayer::PlayPreviewFeedback( TInt aLevel, |
|
224 TTouchLogicalFeedback aFeedback ) |
|
225 { |
|
226 TRACE("CTactileAudioPlayer::PlayPreviewFeedback - Begin"); |
|
227 TInt ret( KErrArgument ); |
|
228 |
|
229 iOriginalVolume = iCurrentVolume; |
|
230 iCurrentVolume = aLevel; |
|
231 iAudioPlayer->SetVolume( ScaledVolume() ); |
|
232 ret = PlayFeedback( aFeedback ); |
|
233 iCurrentVolume = iOriginalVolume; |
|
234 iAudioPlayer->SetVolume( ScaledVolume() ); |
|
235 |
|
236 TRACE("CTactileAudioPlayer::PlayPreviewFeedback - End"); |
|
237 return ret; |
|
238 } |
|
239 |
|
240 // --------------------------------------------------------------------------- |
|
241 // |
|
242 // --------------------------------------------------------------------------- |
|
243 // |
|
244 void CTactileAudioPlayer::MaoscOpenComplete( TInt aError ) |
|
245 { |
|
246 if ( aError == KErrNone ) |
|
247 { |
|
248 iCurrentVolume = iVolumeLevels[0]; |
|
249 iMaxRawVolume = iAudioPlayer->MaxVolume(); |
|
250 iRepository.Get( KTactileFeedbackAudioVolume, iCurrentVolume ); |
|
251 iAudioPlayer->SetVolume( ScaledVolume() ); |
|
252 TRAP_IGNORE( iAudioPlayer->SetDataTypeL( KMMFFourCCCodePCM16 ) ); |
|
253 iState = ETactileAudioReady; |
|
254 } |
|
255 else |
|
256 { |
|
257 TRACE2("CTactileAudioPlayer::MaoscOpenComplete( %d ) failed, will not play feedback", aError ); |
|
258 delete iAudioPlayer; |
|
259 iAudioPlayer = NULL; |
|
260 |
|
261 iState = ETactileAudioError; |
|
262 } |
|
263 } |
|
264 |
|
265 // --------------------------------------------------------------------------- |
|
266 // |
|
267 // --------------------------------------------------------------------------- |
|
268 // |
|
269 void CTactileAudioPlayer::MaoscPlayComplete( TInt aError ) |
|
270 { |
|
271 TRACE("CTactileAudioPlayer::MaoscPlayComplete - Begin"); |
|
272 iAudioPlayer->Stop(); |
|
273 if ( aError == KErrCorrupt ) |
|
274 { |
|
275 TRACE2("CTactileAudioPlayer::MaoscPlayComplete( %d ) failed, will not play feedback", aError ); |
|
276 delete iAudioPlayer; |
|
277 iAudioPlayer = NULL; |
|
278 |
|
279 iState = ETactileAudioError; |
|
280 } |
|
281 else |
|
282 { |
|
283 iState = ETactileAudioReady; |
|
284 } |
|
285 TRACE("CTactileAudioPlayer::MaoscPlayComplete - End"); |
|
286 } |
|
287 |
|
288 // --------------------------------------------------------------------------- |
|
289 // |
|
290 // --------------------------------------------------------------------------- |
|
291 // |
|
292 void CTactileAudioPlayer::MaoscBufferCopied( TInt aError, const TDesC8& /*aBuffer*/ ) |
|
293 { |
|
294 if ( !aError ) |
|
295 { |
|
296 iState = ETactileAudioReady; // may write another sample |
|
297 } |
|
298 else |
|
299 { |
|
300 TRACE2("CTactileAudioPlayer::MaoscPlayComplete( %d ) failed", aError); |
|
301 } |
|
302 } |
|
303 |
|
304 // --------------------------------------------------------------------------- |
|
305 // Settings are now not read completely, as only the .wav -file of basic |
|
306 // feedback is read, and same file is used for sensitive feedback. |
|
307 // Using of separate files for basic and sensitive feedback |
|
308 // can be added later in case necessary. |
|
309 // --------------------------------------------------------------------------- |
|
310 // |
|
311 void CTactileAudioPlayer::ReadSettingsL() |
|
312 { |
|
313 TRACE("CTactileAudioPlayer::ReadSettingsL - Begin"); |
|
314 |
|
315 iVolumeLevels.Reset(); |
|
316 |
|
317 delete iSensitiveFileName; |
|
318 iSensitiveFileName = NULL; |
|
319 |
|
320 delete iBasicFileName; |
|
321 iBasicFileName = NULL; |
|
322 |
|
323 iSensitiveFileName = HBufC::NewL( KMaxFileName ); |
|
324 TPtr sensitiveFileName = iSensitiveFileName->Des(); |
|
325 |
|
326 iBasicFileName = HBufC::NewL( KMaxFileName ); |
|
327 TPtr basicFileName = iBasicFileName->Des(); |
|
328 |
|
329 TInt basicVolumeLevel = 0; |
|
330 TInt sensitiveVolumeLevel = 0; |
|
331 |
|
332 // Read volume values for level 2 |
|
333 iRepository.Get( KTactileAudioWavVolumeBasicLevel2, basicVolumeLevel ); |
|
334 |
|
335 |
|
336 iRepository.Get( KTactileAudioWavVolumeSensitiveLevel2, sensitiveVolumeLevel ); |
|
337 |
|
338 // Read file names |
|
339 iRepository.Get( KTactileAudioWavFileBasicLevel2, basicFileName ); |
|
340 |
|
341 iRepository.Get( KTactileAudioWavFileSensitiveLevel2, sensitiveFileName ); |
|
342 |
|
343 iVolumeLevels.Append( basicVolumeLevel ); |
|
344 iVolumeLevels.Append( sensitiveVolumeLevel ); |
|
345 |
|
346 TRACE("CTactileAudioPlayer::ReadSettingsL() - End"); |
|
347 } |
|
348 |
|
349 |
|
350 // --------------------------------------------------------------------------- |
|
351 // ScaledVolume() |
|
352 // return 100% scaled & sanity checked volume value |
|
353 // --------------------------------------------------------------------------- |
|
354 // |
|
355 TInt CTactileAudioPlayer::ScaledVolume() |
|
356 { |
|
357 if ( iMaxRawVolume == KErrNotFound ) |
|
358 { |
|
359 TRACE( "CTactileAudioPlayer::ScaledVolume() Audio Hardware is not initialized properly" ); |
|
360 return 0; |
|
361 } |
|
362 |
|
363 TInt volume = iMaxRawVolume * iCurrentVolume / 100; |
|
364 |
|
365 if ( volume > iMaxRawVolume ) |
|
366 { |
|
367 // sanity check, we might get anything from cenrep |
|
368 volume = iMaxRawVolume; |
|
369 } |
|
370 |
|
371 TRACE4( "CTactileAudioPlayer::ScaledVolume() iCurrentVolume:%d scales volume to:%d out of iMaxRawVolume:%d", |
|
372 iCurrentVolume, volume, iMaxRawVolume ); |
|
373 |
|
374 return volume; |
|
375 } |
|
376 |
|
377 /* |
|
378 * Wave file structure: Riff header + Wave format chunk + Wave data chunk |
|
379 * |
|
380 * Riff header: |
|
381 * ================================================== |
|
382 * Offset Size Description Value |
|
383 * 0x00 4 Chunk ID "RIFF" |
|
384 * 0x04 4 Chunk Data Size ( file size ) - 8 |
|
385 * 0x08 4 RIFF Type "WAVE" |
|
386 * 0x0c * Wave chunks * |
|
387 * |
|
388 * Wave Format Chunk: |
|
389 * ================================================== |
|
390 * Offset Size Description Value |
|
391 * 0x00 4 Chunk ID "fmt " |
|
392 * 0x04 4 Chunk Data Size 16 + extra format bytes ( 0 for normal wav files) |
|
393 * 0x08 2 Compression code 1...65535 ( 1 for PCM uncompressed) |
|
394 * 0x0a 2 Nbr of channels 1...65535 |
|
395 * 0x0c 4 Sample rate 1...0xFFFFFFFF |
|
396 * 0x10 4 Average bytes per sec |
|
397 * 0x14 2 block align |
|
398 * 0x16 2 siginificant bits per sample |
|
399 * 0x18 2 extra format bytes 0...65535 |
|
400 * 0x1a * extra format bytes, if any * |
|
401 * |
|
402 * Wave Data Chunk: |
|
403 * ================================================== |
|
404 * Offset Size Description Value |
|
405 * 0x00 4 Chunk ID "data" |
|
406 * 0x04 4 Chunk data size |
|
407 * 0x08 * sample data * |
|
408 * |
|
409 */ |
|
410 void CTactileAudioPlayer::ReadSampleL( RFile& aFile, |
|
411 HBufC8*& aDes, |
|
412 TUint& aChannels, |
|
413 TUint& aSampleRate ) |
|
414 { |
|
415 TRACE("CTactileAudioPlayer::ReadSampleL - Start"); |
|
416 const TInt fmtOffset = 0x0c; |
|
417 const TInt dataOffset = fmtOffset + 0x18; |
|
418 |
|
419 TBuf8<KRiffHeaderSize> header; |
|
420 TInt err = aFile.Read( header, KRiffHeaderSize ); |
|
421 if ( err ) |
|
422 { |
|
423 TRACE("CTactileAudioPlayer::ReadSampleL: reading from file failed, aborting"); |
|
424 User::Leave( err ); |
|
425 } |
|
426 |
|
427 TPtr8 p = header.LeftTPtr( 4 ); |
|
428 |
|
429 if ( p.Compare( KRiff ) ) |
|
430 { |
|
431 TRACE("CTactileAudioPlayer::ReadSampleL: no RIFF header found, aborting" ); |
|
432 User::Leave( KErrCorrupt ); |
|
433 } |
|
434 |
|
435 p = header.MidTPtr( 0x08, 4 ); |
|
436 if ( p.Compare( KWave ) ) |
|
437 { |
|
438 TRACE("CTactileAudioPlayer::ReadSampleL: not a WAVE file, aborting" ); |
|
439 User::Leave( KErrCorrupt ); |
|
440 } |
|
441 |
|
442 p = header.MidTPtr( fmtOffset + 0x00, 4 ); |
|
443 if ( p.Compare( KFmt ) ) |
|
444 { |
|
445 TRACE("CTactileAudioPlayer::ReadSampleL: no 'fmt ' chunk found, aborting" ); |
|
446 User::Leave( KErrCorrupt ); |
|
447 } |
|
448 |
|
449 p = header.MidTPtr( dataOffset, 4 ); |
|
450 if ( p.Compare( KData ) ) |
|
451 { |
|
452 TRACE("CTactileAudioPlayer::ReadSampleL: no 'data' chunk found, aborting" ); |
|
453 User::Leave( KErrCorrupt ); |
|
454 } |
|
455 |
|
456 TUint8 lo = header[ fmtOffset + 0x08 ]; |
|
457 TUint8 hi = header[ fmtOffset + 0x08 + 1 ]; |
|
458 if ( !( lo == 1 && hi == 0) ) |
|
459 { |
|
460 TRACE("CTactileAudioPlayer::ReadSampleL: non PCM wav not supported, aborting" ); |
|
461 User::Leave( KErrNotSupported ); |
|
462 } |
|
463 |
|
464 lo = header[ fmtOffset + 0x0a ]; |
|
465 hi = header[ fmtOffset + 0x0a + 1 ]; |
|
466 aChannels = lo; |
|
467 if ( !(aChannels == 1 || aChannels == 2 && hi == 0) ) |
|
468 { |
|
469 TRACE2("CTactileAudioPlayer::ReadSampleL: unsupported number of channels ( %d ), aborting", aChannels ); |
|
470 User::Leave( KErrNotSupported ); |
|
471 } |
|
472 |
|
473 aSampleRate = 0; |
|
474 for ( TInt i = 0; i < 4; i++ ) |
|
475 { |
|
476 lo = header[ fmtOffset + 0x0c + i ]; |
|
477 TUint32 tmp = lo; |
|
478 tmp = tmp << i * 8; |
|
479 |
|
480 aSampleRate = aSampleRate | tmp; |
|
481 } |
|
482 |
|
483 lo = header[ fmtOffset + 0x16 ]; |
|
484 hi = header[ fmtOffset + 0x16 + 1 ]; |
|
485 TUint16 bitsPerSample = hi; |
|
486 bitsPerSample = bitsPerSample << 8; |
|
487 bitsPerSample = bitsPerSample | lo; |
|
488 |
|
489 if ( bitsPerSample != 16 ) |
|
490 { |
|
491 TRACE2("CTactileAudioPlayer::ReadSampleL: %d bits per sample not supported", bitsPerSample ); |
|
492 User::Leave( KErrNotSupported ); |
|
493 } |
|
494 |
|
495 TUint32 bytesPerSample = bitsPerSample / 8; |
|
496 |
|
497 // how many bytes for 6 ms |
|
498 TUint bytesNeeded = ( aSampleRate * aChannels * bytesPerSample * 6 ) / 1000; |
|
499 |
|
500 TInt fsize( 0 ); |
|
501 if ( aFile.Size( fsize ) == KErrNone && fsize >= bytesNeeded + KRiffHeaderSize ) |
|
502 { |
|
503 aDes = HBufC8::NewL( bytesNeeded ); |
|
504 TPtr8 des = aDes->Des(); |
|
505 aFile.Read( des, bytesNeeded ); |
|
506 } |
|
507 else |
|
508 { |
|
509 TRACE("CTactileAudioPlayer::ReadSampleL: Less than 6ms content in file, aborting" ); |
|
510 User::Leave( KErrNotSupported ); |
|
511 } |
|
512 |
|
513 TRACE3("CTactileAudioPlayer::ReadSampleL %dHz %dchannel sample read successfully - End", |
|
514 iSampleRate, iChannels); |
|
515 } |
|
516 |
|
517 // --------------------------------------------------------------------------- |
|
518 // Audio data reading from file and creation of the actual player utility. |
|
519 // |
|
520 // Rest of the initializations are done in MapcInitComplete -function. |
|
521 // |
|
522 // Notice that CMdaAudioOutputStream usage is not a good idea, as it |
|
523 // buffers samples until buffer is full and flushes all in a row. Result is |
|
524 // no feedback first, then a machine gun burst at some completely |
|
525 // unrelated moment. |
|
526 // --------------------------------------------------------------------------- |
|
527 // |
|
528 void CTactileAudioPlayer::CreateWavPlayerL() |
|
529 { |
|
530 TRACE("CTactileAudioPlayer::CreateWavPlayerL - Start"); |
|
531 iState = ETactileAudioInitialising; |
|
532 delete iBasicSample; |
|
533 iBasicSample = NULL; |
|
534 delete iSensitiveSample; |
|
535 iSensitiveSample = NULL; |
|
536 |
|
537 if ( !( iBasicFileName && iBasicFileName->Length() > 0 && |
|
538 iSensitiveFileName && iSensitiveFileName->Length() > 0 )) |
|
539 { |
|
540 TRACE("CTactileAudioPlayer::CreateWavPlayerL filenames missing, aborting"); |
|
541 User::Leave( KErrBadName ); |
|
542 } |
|
543 |
|
544 RFs fs; |
|
545 User::LeaveIfError ( fs.Connect() ); |
|
546 CleanupClosePushL( fs ); |
|
547 |
|
548 RFile file; |
|
549 TInt err = file.Open( fs, *iBasicFileName, EFileRead ); |
|
550 if ( err ) |
|
551 { |
|
552 TRACE2("CTactileAudioPlayer::CreateWavPlayerL could not open %S, aborting", iBasicFileName ); |
|
553 User::Leave( err ); |
|
554 } |
|
555 |
|
556 CleanupClosePushL( file ); |
|
557 ReadSampleL( file, iBasicSample, iChannels, iSampleRate ); |
|
558 CleanupStack::PopAndDestroy(&file); |
|
559 |
|
560 RFile file2; |
|
561 err = file2.Open( fs, *iSensitiveFileName, EFileRead ); |
|
562 if ( err ) |
|
563 { |
|
564 TRACE2("CTactileAudioPlayer::CreateWavPlayerL could not open %S, aborting", iSensitiveFileName ); |
|
565 User::Leave( err ); |
|
566 } |
|
567 |
|
568 CleanupClosePushL( file2 ); |
|
569 |
|
570 TUint sampleRate(0); |
|
571 TUint channels(0); |
|
572 ReadSampleL( file2, iSensitiveSample, channels, sampleRate ); |
|
573 CleanupStack::PopAndDestroy( &file2 ); |
|
574 CleanupStack::PopAndDestroy( &fs ); |
|
575 |
|
576 if ( channels != iChannels || sampleRate != iSampleRate ) |
|
577 { |
|
578 TRACE("CTactileAudioPlayer::CreateWavPlayerL Sample rates and number of channels must be same for both files, aborting"); |
|
579 User::Leave( KErrNotSupported ); |
|
580 } |
|
581 |
|
582 TInt priority = KAudioPriorityKeyPressNonDTMFWithFeedback; |
|
583 TMdaPriorityPreference pref = static_cast<TMdaPriorityPreference>(KAudioPrefKeyPressNonDTMFWithFeedback); |
|
584 |
|
585 iAudioPlayer = CMdaAudioOutputStream::NewL( *this ,priority, pref); |
|
586 |
|
587 TMdaAudioDataSettings streamSettings; |
|
588 switch ( iChannels ) |
|
589 { |
|
590 case 1: |
|
591 streamSettings.iChannels = TMdaAudioDataSettings::EChannelsMono; |
|
592 break; |
|
593 case 2: |
|
594 streamSettings.iChannels = TMdaAudioDataSettings::EChannelsStereo; |
|
595 TRACE("CTactileAudioPlayer::CreateWavPlayerL Warning: stereo wav for feedback"); |
|
596 break; |
|
597 default: |
|
598 TRACE2("CTactileAudioPlayer::CreateWavPlayerL: unsupported number of channels %d, aborting", iChannels ); |
|
599 User::Leave( KErrNotSupported ); |
|
600 break; |
|
601 } |
|
602 |
|
603 // there must be easier way to do this... |
|
604 switch( iSampleRate ) |
|
605 { |
|
606 case 48000: |
|
607 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate48000Hz; |
|
608 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate48000Hz; |
|
609 break; |
|
610 case 44100: |
|
611 TRACE2("CTactileAudioPlayer::CreateWavPlayerL: warning, samplerate %d causes performance problem", iSampleRate ); |
|
612 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate44100Hz; |
|
613 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate44100Hz; |
|
614 break; |
|
615 case 32000: |
|
616 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate32000Hz; |
|
617 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate32000Hz; |
|
618 break; |
|
619 case 24000: |
|
620 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate24000Hz; |
|
621 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate24000Hz; |
|
622 break; |
|
623 case 16000: |
|
624 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate16000Hz; |
|
625 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate16000Hz; |
|
626 break; |
|
627 case 12000: |
|
628 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate12000Hz; |
|
629 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate12000Hz; |
|
630 break; |
|
631 case 11025: |
|
632 TRACE2("CTactileAudioPlayer::CreateWavPlayerL: warning, samplerate %d causes performance problem",iSampleRate ); |
|
633 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate11025Hz; |
|
634 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate11025Hz; |
|
635 break; |
|
636 case 8000: |
|
637 streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz; |
|
638 streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate8000Hz; |
|
639 break; |
|
640 default: |
|
641 TRACE2("CTactileAudioPlayer::CreateWavPlayerL: unsupported samplerate %d, aborting",iSampleRate ); |
|
642 User::Leave( KErrNotSupported ); |
|
643 break; |
|
644 } |
|
645 |
|
646 iAudioPlayer->Open( &streamSettings ); |
|
647 |
|
648 TRACE("CTactileAudioPlayer::CreateWavPlayerL - End"); |
|
649 } |
|
650 |
|
651 // --------------------------------------------------------------------------- |
|
652 // |
|
653 // --------------------------------------------------------------------------- |
|
654 // |
|
655 void CTactileAudioPlayer::HandleNotifyInt( TUint32 aId, TInt aNewValue ) |
|
656 { |
|
657 TRACE("CTactileTonePlayer::HandleNotifyInt - Begin"); |
|
658 if ( aId == KTactileFeedbackAudioVolume ) |
|
659 { |
|
660 iCurrentVolume = aNewValue; |
|
661 iAudioPlayer->SetVolume( ScaledVolume() ); |
|
662 } |
|
663 TRACE("CTactileTonePlayer::HandleNotifyInt - End"); |
|
664 } |
|
665 |
|
666 |
|
667 //--------------------------------------------------------------------------- |
|
668 // ImplementationTable[] |
|
669 // |
|
670 //--------------------------------------------------------------------------- |
|
671 // |
|
672 const TImplementationProxy ImplementationTable[] = |
|
673 { |
|
674 IMPLEMENTATION_PROXY_ENTRY( 0x2002133A, CTactileAudioPlayer::NewL ) |
|
675 }; |
|
676 |
|
677 //--------------------------------------------------------------------------- |
|
678 // TImplementationProxy* ImplementationGroupProxy() |
|
679 // |
|
680 //--------------------------------------------------------------------------- |
|
681 // |
|
682 EXPORT_C const TImplementationProxy* ImplementationGroupProxy( TInt& aTableCount ) |
|
683 { |
|
684 aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy); |
|
685 return ImplementationTable; |
|
686 } |
|
687 |
|
688 |
|
689 |
|
690 // End of file |