|
1 // Copyright (c) 2007-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 #ifndef MDASOUNDADAPTERBODY_H |
|
17 #define MDASOUNDADAPTERBODY_H |
|
18 |
|
19 #include "mdasoundadapter.h" |
|
20 #include <d32soundsc.h> |
|
21 #include <e32base.h> |
|
22 #include <e32std.h> |
|
23 |
|
24 /** |
|
25 Panic category and codes for the mdasoundadapter |
|
26 */ |
|
27 _LIT(KSoundAdapterPanicCategory, "mdasoundadapter"); |
|
28 enum TSoundAdapterPanicCodes |
|
29 { |
|
30 EDeviceNotOpened, |
|
31 EPanicPartialBufferConverterNotSupported, |
|
32 EBadState, |
|
33 ENoClientPlayRequest, |
|
34 EFifoEmpty, |
|
35 EFifoFull |
|
36 }; |
|
37 |
|
38 //Structure used to map samples per second to the corresponding enums in RSoundSc |
|
39 struct TSampleRateEnumTable |
|
40 { |
|
41 TInt iRate; |
|
42 TSoundRate iRateEnum; |
|
43 TUint iRateConstant; |
|
44 }; |
|
45 |
|
46 //Table that maps given samples per second to the corresponding enums in RSoundSc |
|
47 const TSampleRateEnumTable KRateEnumLookup[] = |
|
48 { |
|
49 {48000,ESoundRate48000Hz,KSoundRate48000Hz}, |
|
50 {44100,ESoundRate44100Hz,KSoundRate44100Hz}, |
|
51 {32000,ESoundRate32000Hz,KSoundRate32000Hz}, |
|
52 {24000,ESoundRate24000Hz,KSoundRate24000Hz}, |
|
53 {22050,ESoundRate22050Hz,KSoundRate22050Hz}, |
|
54 {16000,ESoundRate16000Hz,KSoundRate16000Hz}, |
|
55 {12000,ESoundRate12000Hz,KSoundRate12000Hz}, |
|
56 {11025,ESoundRate11025Hz,KSoundRate11025Hz}, |
|
57 {8000, ESoundRate8000Hz, KSoundRate8000Hz} |
|
58 }; |
|
59 //Structure used to map linear value of the volume to the decibel value. |
|
60 struct TLinearToDbTable |
|
61 { |
|
62 TInt iLiniearValue; |
|
63 TInt iDBValue; |
|
64 }; |
|
65 |
|
66 |
|
67 //Table that maps given linear value of volume to the corresponding decibel value. |
|
68 const TLinearToDbTable KLinerToDbConstantLookup[] = |
|
69 { |
|
70 {0,0}, |
|
71 {1,158}, |
|
72 {2,170}, |
|
73 {3,177}, |
|
74 {4,182}, |
|
75 {5,186}, |
|
76 {6,189}, |
|
77 {7,192}, |
|
78 {8,194}, |
|
79 {9,196}, |
|
80 {10,198}, |
|
81 {11,200}, |
|
82 {12,201}, |
|
83 {13,203}, |
|
84 {14,204}, |
|
85 {15,205}, |
|
86 {16,206}, |
|
87 {17,207}, |
|
88 {18,208}, |
|
89 {19,209}, |
|
90 {20,210}, |
|
91 {21,211}, |
|
92 {22,212}, |
|
93 {23,213}, |
|
94 {24,213}, |
|
95 {25,214}, |
|
96 {26,215}, |
|
97 {27,215}, |
|
98 {28,216}, |
|
99 {29,217}, |
|
100 {30,217}, |
|
101 {31,218}, |
|
102 {32,218}, |
|
103 {33,219}, |
|
104 {34,219}, |
|
105 {35,220}, |
|
106 {36,220}, |
|
107 {37,221}, |
|
108 {38,221}, |
|
109 {39,222}, |
|
110 {40,222}, |
|
111 {41,223}, |
|
112 {42,223}, |
|
113 {43,224}, |
|
114 {44,224}, |
|
115 {45,224}, |
|
116 {46,225}, |
|
117 {47,225}, |
|
118 {48,225}, |
|
119 {49,226}, |
|
120 {50,226}, |
|
121 {51,226}, |
|
122 {52,227}, |
|
123 {53,227}, |
|
124 {54,227}, |
|
125 {55,228}, |
|
126 {56,228}, |
|
127 {57,228}, |
|
128 {58,229}, |
|
129 {59,229}, |
|
130 {60,229}, |
|
131 {61,230}, |
|
132 {62,230}, |
|
133 {63,230}, |
|
134 {64,230}, |
|
135 {65,231}, |
|
136 {66,231}, |
|
137 {67,231}, |
|
138 {68,231}, |
|
139 {69,232}, |
|
140 {70,232}, |
|
141 {71,232}, |
|
142 {72,232}, |
|
143 {73,233}, |
|
144 {74,233}, |
|
145 {75,233}, |
|
146 {76,233}, |
|
147 {77,234}, |
|
148 {78,234}, |
|
149 {79,234}, |
|
150 {80,234}, |
|
151 {81,235}, |
|
152 {82,235}, |
|
153 {83,235}, |
|
154 {84,235}, |
|
155 {85,235}, |
|
156 {86,236}, |
|
157 {87,236}, |
|
158 {88,236}, |
|
159 {89,236}, |
|
160 {90,236}, |
|
161 {91,237}, |
|
162 {92,237}, |
|
163 {93,237}, |
|
164 {94,237}, |
|
165 {95,237}, |
|
166 {96,237}, |
|
167 {97,238}, |
|
168 {98,238}, |
|
169 {99,238}, |
|
170 {100,238}, |
|
171 {101,238}, |
|
172 {102,239}, |
|
173 {103,239}, |
|
174 {104,239}, |
|
175 {105,239}, |
|
176 {106,239}, |
|
177 {107,239}, |
|
178 {108,240}, |
|
179 {109,240}, |
|
180 {110,240}, |
|
181 {111,240}, |
|
182 {112,240}, |
|
183 {113,240}, |
|
184 {114,240}, |
|
185 {115,241}, |
|
186 {116,241}, |
|
187 {117,241}, |
|
188 {118,241}, |
|
189 {119,241}, |
|
190 {120,241}, |
|
191 {121,241}, |
|
192 {122,242}, |
|
193 {123,242}, |
|
194 {124,242}, |
|
195 {125,242}, |
|
196 {126,242}, |
|
197 {127,242}, |
|
198 {128,242}, |
|
199 {129,243}, |
|
200 {130,243}, |
|
201 {131,243}, |
|
202 {132,243}, |
|
203 {133,243}, |
|
204 {134,243}, |
|
205 {135,243}, |
|
206 {136,244}, |
|
207 {137,244}, |
|
208 {138,244}, |
|
209 {139,244}, |
|
210 {140,244}, |
|
211 {141,244}, |
|
212 {142,244}, |
|
213 {143,244}, |
|
214 {144,245}, |
|
215 {145,245}, |
|
216 {146,245}, |
|
217 {147,245}, |
|
218 {148,245}, |
|
219 {149,245}, |
|
220 {150,245}, |
|
221 {151,245}, |
|
222 {152,245}, |
|
223 {153,246}, |
|
224 {154,246}, |
|
225 {155,246}, |
|
226 {156,246}, |
|
227 {157,246}, |
|
228 {158,246}, |
|
229 {159,246}, |
|
230 {160,246}, |
|
231 {161,246}, |
|
232 {162,247}, |
|
233 {163,247}, |
|
234 {164,247}, |
|
235 {165,247}, |
|
236 {166,247}, |
|
237 {167,247}, |
|
238 {168,247}, |
|
239 {169,247}, |
|
240 {170,247}, |
|
241 {171,247}, |
|
242 {172,248}, |
|
243 {173,248}, |
|
244 {174,248}, |
|
245 {175,248}, |
|
246 {176,248}, |
|
247 {177,248}, |
|
248 {178,248}, |
|
249 {179,248}, |
|
250 {180,248}, |
|
251 {181,248}, |
|
252 {182,249}, |
|
253 {183,249}, |
|
254 {184,249}, |
|
255 {185,249}, |
|
256 {186,249}, |
|
257 {187,249}, |
|
258 {188,249}, |
|
259 {189,249}, |
|
260 {190,249}, |
|
261 {191,249}, |
|
262 {192,250}, |
|
263 {193,250}, |
|
264 {194,250}, |
|
265 {195,250}, |
|
266 {196,250}, |
|
267 {197,250}, |
|
268 {198,250}, |
|
269 {199,250}, |
|
270 {200,250}, |
|
271 {201,250}, |
|
272 {202,250}, |
|
273 {203,250}, |
|
274 {204,251}, |
|
275 {205,251}, |
|
276 {206,251}, |
|
277 {207,251}, |
|
278 {208,251}, |
|
279 {209,251}, |
|
280 {210,251}, |
|
281 {211,251}, |
|
282 {212,251}, |
|
283 {213,251}, |
|
284 {214,251}, |
|
285 {215,251}, |
|
286 {216,252}, |
|
287 {217,252}, |
|
288 {218,252}, |
|
289 {219,252}, |
|
290 {220,252}, |
|
291 {221,252}, |
|
292 {222,252}, |
|
293 {223,252}, |
|
294 {224,252}, |
|
295 {225,252}, |
|
296 {226,252}, |
|
297 {227,252}, |
|
298 {228,252}, |
|
299 {229,253}, |
|
300 {230,253}, |
|
301 {231,253}, |
|
302 {232,253}, |
|
303 {233,253}, |
|
304 {234,253}, |
|
305 {235,253}, |
|
306 {236,253}, |
|
307 {237,253}, |
|
308 {238,253}, |
|
309 {239,253}, |
|
310 {240,253}, |
|
311 {241,253}, |
|
312 {242,254}, |
|
313 {243,254}, |
|
314 {244,254}, |
|
315 {245,254}, |
|
316 {246,254}, |
|
317 {247,254}, |
|
318 {248,254}, |
|
319 {249,254}, |
|
320 {250,254}, |
|
321 {251,254}, |
|
322 {252,254}, |
|
323 {253,254}, |
|
324 {254,254}, |
|
325 {255,254} |
|
326 }; |
|
327 |
|
328 // Total Number of sample rates |
|
329 const TUint KNumSampleRates = 9; |
|
330 // Number of shared chunk buffers used for playing |
|
331 // Each buffer is permanently mapped, via an index number, to a particular buffer in the chunk |
|
332 // The esoundsc.ldd can only handle a max of 8 pending play requests, therefore no point in having |
|
333 // more than 8 play buffers... |
|
334 const TUint KPlaySharedChunkBuffers = 8; |
|
335 // Size of RSoundSc play buffers |
|
336 const TUint KPlaySharedChunkBufferSize = 4096; |
|
337 |
|
338 //Number of shared chunk buffers used for recording |
|
339 const TUint KRecordMaxSharedChunkBuffers = 8; |
|
340 // Size of RSoundSc record buffers |
|
341 const TUint KRecordSharedChunkBufferSize = 4096; |
|
342 |
|
343 //Shared chunk driver does not support max. buffer size. 16K is given in order to simulate the old driver behavior. |
|
344 const TUint KMaxBufferSize = 0x4000; |
|
345 |
|
346 class TPlaySharedChunkBufConfig : public TSharedChunkBufConfigBase |
|
347 { |
|
348 public: |
|
349 TInt iBufferOffsetList[KPlaySharedChunkBuffers]; |
|
350 }; |
|
351 |
|
352 class TRecordSharedChunkBufConfig : public TSharedChunkBufConfigBase |
|
353 { |
|
354 public: |
|
355 TInt iBufferOffsetList[KRecordMaxSharedChunkBuffers]; |
|
356 }; |
|
357 |
|
358 class CChannelAndSampleRateConverter; // forward dec |
|
359 |
|
360 GLDEF_C void Panic(TSoundAdapterPanicCodes aPanicCode);//forward declaration |
|
361 |
|
362 // RFifo class which manages a fifo of up to COUNT items of type T |
|
363 template<typename T, TUint32 COUNT> class RFifo |
|
364 { |
|
365 public: |
|
366 RFifo() |
|
367 : iWriteIndex(0), iReadIndex(0) |
|
368 {} |
|
369 TBool IsEmpty() const |
|
370 { |
|
371 return iWriteIndex == iReadIndex; |
|
372 } |
|
373 TBool IsFull() const |
|
374 { |
|
375 // Full if writing one more item would make iWriteIndex equal to iReadIndex |
|
376 TUint32 next = NextIndex(iWriteIndex); |
|
377 return next == iReadIndex; |
|
378 } |
|
379 /// Push item into FIFO. Does not take ownership. Will PANIC with EFifoFull if full. |
|
380 void Push(const T &aItem) |
|
381 { |
|
382 if(IsFull()) |
|
383 { |
|
384 Panic(EFifoFull); |
|
385 } |
|
386 iFifo[iWriteIndex] = aItem; |
|
387 iWriteIndex = NextIndex(iWriteIndex); |
|
388 } |
|
389 /// Pop item from FIFO. Will PANIC with EFifoEmpty if empty |
|
390 T Pop() |
|
391 { |
|
392 if(IsEmpty()) |
|
393 { |
|
394 Panic(EFifoEmpty); |
|
395 } |
|
396 TUint32 tmp = iReadIndex; |
|
397 iReadIndex = NextIndex(iReadIndex); |
|
398 return iFifo[tmp]; |
|
399 } |
|
400 |
|
401 /// Peek first item from FIFO. Will PANIC with EFifoEmpty if empty |
|
402 T Peek() |
|
403 { |
|
404 if(IsEmpty()) |
|
405 { |
|
406 Panic(EFifoEmpty); |
|
407 } |
|
408 return iFifo[iReadIndex]; |
|
409 } |
|
410 TUint Length() const |
|
411 { |
|
412 TUint len; |
|
413 if(iWriteIndex >= iReadIndex) |
|
414 { |
|
415 len = iWriteIndex - iReadIndex; |
|
416 } |
|
417 else |
|
418 { |
|
419 len = COUNT+1 - (iReadIndex - iWriteIndex); |
|
420 } |
|
421 return len; |
|
422 } |
|
423 private: |
|
424 TUint32 NextIndex(TUint32 aIndex) const |
|
425 { |
|
426 ++aIndex; |
|
427 aIndex %= (COUNT+1); |
|
428 return aIndex; |
|
429 } |
|
430 T iFifo[COUNT+1]; |
|
431 TUint32 iWriteIndex; |
|
432 TUint32 iReadIndex; |
|
433 }; |
|
434 |
|
435 |
|
436 |
|
437 //Body class for the adapter |
|
438 NONSHARABLE_CLASS( RMdaDevSound::CBody ): public CBase |
|
439 { |
|
440 public: |
|
441 //This class handles the play/record completions from the new sound driver |
|
442 NONSHARABLE_CLASS( CPlayer ) : public CActive |
|
443 { |
|
444 public: |
|
445 explicit CPlayer(TInt aPriority, RMdaDevSound::CBody& aParent, TInt aIndex); |
|
446 ~CPlayer(); |
|
447 void RunL(); |
|
448 TInt RunError(TInt aError); |
|
449 void DoCancel(); |
|
450 void PlayData(TUint aChunkOffset, TInt aLength); |
|
451 |
|
452 TUint GetPlayerIndex() const; |
|
453 |
|
454 private: |
|
455 RMdaDevSound::CBody& iParent; |
|
456 const TUint iIndex; // index of this object in parent |
|
457 |
|
458 TInt iBufferOffset; |
|
459 TInt iBufferLength; |
|
460 }; |
|
461 |
|
462 |
|
463 NONSHARABLE_CLASS( CRecorder ) : public CActive |
|
464 { |
|
465 public: |
|
466 explicit CRecorder(TInt aPriority, RMdaDevSound::CBody& aParent); |
|
467 ~CRecorder(); |
|
468 void RunL(); |
|
469 TInt RunError(TInt aError); |
|
470 void DoCancel(); |
|
471 void RecordData(TInt& aLength); |
|
472 |
|
473 private: |
|
474 RMdaDevSound::CBody& iParent; |
|
475 |
|
476 TInt iBufferOffset; |
|
477 TInt iBufferLength; |
|
478 }; |
|
479 |
|
480 enum TStateEnum |
|
481 { |
|
482 ENotReady, |
|
483 EStopped, |
|
484 ERecording, |
|
485 ERecordingPausedInHw, |
|
486 ERecordingPausedInSw, |
|
487 EPlaying, |
|
488 EPlayingPausedInHw, // ie. Play request pending on h/w and paused |
|
489 EPlayingPausedInSw, // ie. Driver not playing or paused |
|
490 EPlayingUnderrun |
|
491 }; |
|
492 |
|
493 NONSHARABLE_CLASS( TState ) |
|
494 { |
|
495 public: |
|
496 TState(TStateEnum aState) : iState(aState) {} |
|
497 const TText8 *Name() const; |
|
498 TState &operator=(TStateEnum aNewState); |
|
499 operator TStateEnum() const { return iState; } |
|
500 private: |
|
501 TStateEnum iState; |
|
502 }; |
|
503 |
|
504 class TFormatData |
|
505 { |
|
506 public: |
|
507 inline TFormatData(): |
|
508 iSampleRate(8000), iRequestedChannels(1) // default |
|
509 { |
|
510 } |
|
511 public: |
|
512 CChannelAndSampleRateConverter* iConverter; |
|
513 TInt iSampleRate; |
|
514 TInt iActualRate; |
|
515 TInt iRequestedChannels; |
|
516 TInt iActualChannels; |
|
517 }; |
|
518 |
|
519 public: |
|
520 ~CBody(); |
|
521 static CBody* NewL(); |
|
522 TInt Open(TInt aUnit=KNullUnit); |
|
523 TVersion VersionRequired() const; |
|
524 TInt IsMdaSound(); |
|
525 void PlayFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported); |
|
526 void GetPlayFormat(TCurrentSoundFormatBuf& aFormat); |
|
527 TInt SetPlayFormat(const TCurrentSoundFormatBuf& aFormat); |
|
528 TInt PlayVolume(); |
|
529 void SetPlayVolume(TInt aVolume); |
|
530 void SetVolume(TInt aLogarithmicVolume); |
|
531 void CancelPlayData(); |
|
532 void RecordFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported); |
|
533 void GetRecordFormat(TCurrentSoundFormatBuf& aFormat); |
|
534 TInt SetRecordFormat(const TCurrentSoundFormatBuf& aFormat); |
|
535 TInt RecordLevel(); |
|
536 void SetRecordLevel(TInt aLevel); |
|
537 void CancelRecordData(); |
|
538 void FlushRecordBuffer(); |
|
539 TInt BytesPlayed(); |
|
540 void ResetBytesPlayed(); |
|
541 void PausePlayBuffer(); |
|
542 void ResumePlaying(); |
|
543 void PauseRecordBuffer(); |
|
544 void ResumeRecording(); |
|
545 TInt GetTimePlayed(TTimeIntervalMicroSeconds& aTimePlayed); |
|
546 void Close(); |
|
547 TInt Handle(); |
|
548 void PlayData(TRequestStatus& aStatus,const TDesC8& aData); |
|
549 void RecordData(TRequestStatus& aStatus,TDes8& aData); |
|
550 void NotifyRecordError(TRequestStatus& aStatus); |
|
551 void NotifyPlayError(TRequestStatus& aStatus); |
|
552 void CancelNotifyPlayError(); |
|
553 void CancelNotifyRecordError(); |
|
554 void FlushPlayBuffer(); |
|
555 //internal methods added to reduce the code |
|
556 void FormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported, RSoundSc& aDevice); |
|
557 void GetFormat(TCurrentSoundFormatBuf& aFormat, RSoundSc& aDevice, const TFormatData &aFormatData); |
|
558 TInt SetFormat(const TCurrentSoundFormatBuf& aFormat, RSoundSc& aDevice, TFormatData &aFormatData); |
|
559 |
|
560 //for players |
|
561 void SoundDeviceError(TInt aError); |
|
562 RSoundSc& PlaySoundDevice(); |
|
563 RSoundSc& RecordSoundDevice(); |
|
564 const TState &State() const; |
|
565 void BufferFilled(TInt aError); |
|
566 |
|
567 // Called whenever a player becomes inactive. |
|
568 // This includes driver request ok, driver request failed, CPlayer:::RunError invoked. |
|
569 void PlayRequestHasCompleted(CPlayer *aPlayer, TInt aStatus, TBool aDueToCancelCommand); |
|
570 |
|
571 private: |
|
572 CBody(); |
|
573 void ConstructL(); |
|
574 |
|
575 TInt NegotiateFormat(const TCurrentSoundFormatBuf& aFormat, RSoundSc& aDevice, TFormatData &aFormatData); |
|
576 |
|
577 void StartPlayersAndUpdateState(); |
|
578 void StartRecordRequest(); |
|
579 |
|
580 const char *StateName() const; |
|
581 |
|
582 TBool InRecordMode() const; |
|
583 TBool InPlayMode() const; |
|
584 |
|
585 TUint32 CurrentTimeInMsec() const; |
|
586 TUint64 BytesPlayed64(); |
|
587 |
|
588 private: |
|
589 RSoundSc iPlaySoundDevice; |
|
590 RChunk iPlayChunk;//handle to the shared chunk |
|
591 RSoundSc iRecordSoundDevice; |
|
592 RChunk iRecordChunk;//handle to the shared chunk |
|
593 TState iState; |
|
594 |
|
595 //Playing Properties |
|
596 TPlaySharedChunkBufConfig iPlayBufferConfig; |
|
597 TInt iDeviceBufferLength; |
|
598 |
|
599 //Stores the status of CDataPathPlayer |
|
600 TRequestStatus* iClientPlayStatus; |
|
601 TPtrC8 iClientPlayData; |
|
602 //Stores the status of CSoundDevPlayErrorReceiver |
|
603 TRequestStatus* iClientPlayErrorStatus; |
|
604 RBuf8 iConvertedPlayData; |
|
605 RBuf8 iSavedTrailingData; |
|
606 |
|
607 CPlayer* iPlayers[KPlaySharedChunkBuffers]; |
|
608 RFifo<CPlayer *, KPlaySharedChunkBuffers> iFreePlayers; |
|
609 RFifo<TUint32, KPlaySharedChunkBuffers> iActivePlayRequestSizes; |
|
610 |
|
611 TInt iRequestMinSize; |
|
612 TUint iRequestMinMask; |
|
613 |
|
614 //Recording Properties |
|
615 TRecordSharedChunkBufConfig iRecordBufferConfig; |
|
616 TInt iBufferOffset; |
|
617 TInt iBufferLength; |
|
618 |
|
619 //Stores the status of CDataPathRecorder |
|
620 TRequestStatus* iClientRecordStatus; |
|
621 //Stores the status of CSoundDevRecordErrorReceiver |
|
622 TRequestStatus* iClientRecordErrorStatus; |
|
623 TDes8* iClientRecordData;//stores the data pointer from datapath recorder |
|
624 RBuf8 iBufferedRecordData; // Used if RSoundSc returns more data than current client request requires. |
|
625 |
|
626 CRecorder* iRecorder; // We only need one recorder. The driver will buffer data for us. |
|
627 |
|
628 TBool iUnderFlowReportedSinceLastPlayOrRecordRequest; |
|
629 |
|
630 TUint64 iBytesPlayed; |
|
631 TUint32 iNTickPeriodInUsec; |
|
632 TUint32 iStartTime; // Time when previous driver PlayData completed (or first was issued) in msec |
|
633 TUint32 iPauseTime; // Time when pause started in msec |
|
634 TUint64 iPausedBytesPlayed; |
|
635 |
|
636 TFormatData iPlayFormatData; |
|
637 TFormatData iRecordFormatData; |
|
638 }; |
|
639 #endif |