|
1 /* |
|
2 * Copyright (c) 2006 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: DTMF RTP payload decoder for named telephone events |
|
15 * and tones. |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 // INCLUDES |
|
23 #include <mmf/server/mmfdatabuffer.h> |
|
24 #include "dtmfpayloaddecoder.h" |
|
25 #include "streamformatter.h" |
|
26 |
|
27 // CONSTANTS |
|
28 const TInt KBitIndex = 8; |
|
29 const TInt KReservedBits = 4; |
|
30 const TUint KMaxEventInteger = 9; |
|
31 |
|
32 #ifdef VOIP_TRACE_ENABLED |
|
33 #include <voip_trace.h> |
|
34 #endif |
|
35 |
|
36 // ======== MEMBER FUNCTIONS ======== |
|
37 |
|
38 |
|
39 // --------------------------------------------------------------------------- |
|
40 // CDTMFPayloadDecoder::CDTMFPayloadDecoder |
|
41 // C++ default constructor can NOT contain any code, that |
|
42 // might leave. |
|
43 // --------------------------------------------------------------------------- |
|
44 // |
|
45 CDTMFPayloadDecoder::CDTMFPayloadDecoder() |
|
46 { |
|
47 } |
|
48 |
|
49 // --------------------------------------------------------------------------- |
|
50 // CDTMFPayloadDecoder::NewL |
|
51 // Two-phased constructor. |
|
52 // --------------------------------------------------------------------------- |
|
53 // |
|
54 CDTMFPayloadDecoder* CDTMFPayloadDecoder::NewL() |
|
55 { |
|
56 DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::NewL") ); |
|
57 #ifdef VOIP_TRACE_ENABLED |
|
58 VoipTrace( "%x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_NEWL ); |
|
59 #endif |
|
60 |
|
61 CDTMFPayloadDecoder* self = new( ELeave ) CDTMFPayloadDecoder; |
|
62 return self; |
|
63 } |
|
64 |
|
65 // --------------------------------------------------------------------------- |
|
66 // CDTMFPayloadDecoder::~CDTMFPayloadDecoder |
|
67 // Destructor. |
|
68 // --------------------------------------------------------------------------- |
|
69 // |
|
70 CDTMFPayloadDecoder::~CDTMFPayloadDecoder() |
|
71 { |
|
72 DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::~CDTMFPayloadDecoder") ); |
|
73 #ifdef VOIP_TRACE_ENABLED |
|
74 VoipTrace( "%x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DESTRUCTOR ); |
|
75 #endif |
|
76 |
|
77 iEventArray.Reset(); |
|
78 } |
|
79 |
|
80 // --------------------------------------------------------------------------- |
|
81 // CDTMFPayloadDecoder::DecodeEventPayload |
|
82 // Decodes one DTMF digit or mutually exclusive events from Event Payload |
|
83 // Format packet. |
|
84 // --------------------------------------------------------------------------- |
|
85 // |
|
86 /* |
|
87 0 1 2 3 |
|
88 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
|
89 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
90 | event |E|R| volume | duration | |
|
91 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
92 */ |
|
93 TInt CDTMFPayloadDecoder::DecodeEventPayload( CMMFBuffer* aSourceBuffer, |
|
94 RArray<TDTMFEventPayloadInfo>& aEventInfos ) |
|
95 { |
|
96 DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::DecodeEventPayload") ); |
|
97 #ifdef VOIP_TRACE_ENABLED |
|
98 VoipTrace( "%x %x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DECEVENTPAYLOAD, |
|
99 aSourceBuffer ); |
|
100 #endif |
|
101 |
|
102 if ( EDTMFPayloadFormatRedEvents == iPayloadFormat ) |
|
103 { |
|
104 return DecodeRedundantEventPayload( aSourceBuffer, aEventInfos ); |
|
105 } |
|
106 |
|
107 if ( aSourceBuffer ) |
|
108 { |
|
109 TDes8& dataDes = |
|
110 static_cast<CMMFDataBuffer*>( aSourceBuffer )->Data(); |
|
111 const TUint8* seekPtr = dataDes.Ptr(); |
|
112 TInt events = dataDes.Length( ) / KEventBlockLengthInBytes; |
|
113 |
|
114 TStreamDecoder streamDecoder; |
|
115 |
|
116 streamDecoder.Initialize( const_cast<TUint8*>( seekPtr ), 0, 0 ); |
|
117 |
|
118 while ( events-- ) |
|
119 { |
|
120 // Decode Event Field |
|
121 TInt eventCode = streamDecoder.Decode( KEventFieldBits ); |
|
122 TChar charRepresentation; |
|
123 if ( KErrNone == ConvertToChar( eventCode, charRepresentation ) ) |
|
124 { |
|
125 iDecodedEventInfo.SetEvent( charRepresentation ); |
|
126 |
|
127 // Decode end bit for final packet |
|
128 iDecodedEventInfo.SetEndBit( streamDecoder.Decode( 1 ) ); |
|
129 |
|
130 // Decode reserved bit |
|
131 streamDecoder.Decode( 1 ); |
|
132 |
|
133 // Decode volume field. |
|
134 // Volume field must be ignored if event |
|
135 // is not DTMF digit (RFC 2833) |
|
136 if ( KEventCodeForD > eventCode ) |
|
137 { |
|
138 iDecodedEventInfo.SetVolume( |
|
139 streamDecoder.Decode(KVolFieldBits) ); |
|
140 } |
|
141 else |
|
142 { |
|
143 streamDecoder.Decode( KVolFieldBits ); |
|
144 iDecodedEventInfo.SetVolume( 0 ); |
|
145 } |
|
146 |
|
147 // Decode duration field |
|
148 iDecodedEventInfo.SetDuration( |
|
149 streamDecoder.Decode(KDurationFieldBits) ); |
|
150 |
|
151 // Time stamp from RTP header |
|
152 iDecodedEventInfo.SetTimeStamp( iCurTimeStamp ); |
|
153 |
|
154 aEventInfos.Append( iDecodedEventInfo ); |
|
155 |
|
156 DP_DTMF_DECODE5( |
|
157 _L( "Decoded event: %d, EndBit: %d, Volume: %d, Duration: %d" ), |
|
158 static_cast<TUint>( iDecodedEventInfo.Event() ), |
|
159 iDecodedEventInfo.EndBit(), |
|
160 iDecodedEventInfo.Volume(), |
|
161 iDecodedEventInfo.Duration() ); |
|
162 } |
|
163 else |
|
164 { |
|
165 DP_DTMF_DECODE( _L( "CDTMFPayloadDecoder::DecodeEventPayload - Not supported event! ") ); |
|
166 } |
|
167 } |
|
168 |
|
169 return KErrNone; |
|
170 } |
|
171 else |
|
172 { |
|
173 return KErrArgument; |
|
174 } |
|
175 } |
|
176 |
|
177 // --------------------------------------------------------------------------- |
|
178 // CDTMFPayloadDecoder::DecodeRedundantEventPayload |
|
179 // Decodes events from Event Payload Format where is used Multi-Event |
|
180 // Redundancy. |
|
181 // --------------------------------------------------------------------------- |
|
182 // |
|
183 /* |
|
184 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
185 |F| block PT | timestamp offset | block length | |
|
186 |1| 97 | 11200 | 4 | |
|
187 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
188 |F| block PT | timestamp offset | block length | |
|
189 |1| 97 | 11200 - 6400 = 4800 | 4 | |
|
190 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
191 |F| Block PT | |
|
192 |0| 97 | |
|
193 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
194 | digit |E R| volume | duration | |
|
195 | 9 |1 0| 7 | 1600 | |
|
196 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
197 | digit |E R| volume | duration | |
|
198 | 1 |1 0| 10 | 2000 | |
|
199 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
200 | digit |E R| volume | duration | |
|
201 | 1 |0 0| 20 | 400 | |
|
202 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
203 */ |
|
204 TInt CDTMFPayloadDecoder::DecodeRedundantEventPayload( |
|
205 CMMFBuffer* aSourceBuffer, |
|
206 RArray<TDTMFEventPayloadInfo>& aEventInfos ) |
|
207 { |
|
208 DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::DecodeRedundantEventPayload") ); |
|
209 |
|
210 #ifdef VOIP_TRACE_ENABLED |
|
211 VoipTrace( "%x %x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DECREDEVPL, aSourceBuffer ); |
|
212 #endif |
|
213 |
|
214 if ( aSourceBuffer ) |
|
215 { |
|
216 TDes8& dataDes = |
|
217 static_cast<CMMFDataBuffer*>( aSourceBuffer )->Data(); |
|
218 const TUint8* seekPtr = dataDes.Ptr(); |
|
219 |
|
220 TStreamDecoder streamDecoder; |
|
221 |
|
222 streamDecoder.Initialize( const_cast<TUint8*>( seekPtr ), 0, 0 ); |
|
223 |
|
224 aEventInfos.Reset(); |
|
225 |
|
226 // Count events in a payload from the redundancy headers |
|
227 TInt eventCount( 0 ); |
|
228 TBool FBitSet( ETrue ); |
|
229 RArray< TTimeIntervalMicroSeconds32 > timeStamps; |
|
230 |
|
231 while ( FBitSet ) |
|
232 { |
|
233 eventCount++; |
|
234 |
|
235 FBitSet = static_cast<TBool>( streamDecoder.Decode( 1 ) ); |
|
236 streamDecoder.Decode( KBlockPTBits ); |
|
237 |
|
238 if ( FBitSet ) |
|
239 { |
|
240 TUint offset = streamDecoder.Decode( KTimeStampOffsetBits ); |
|
241 timeStamps.Append( TTimeIntervalMicroSeconds32( |
|
242 iCurTimeStamp.Int() - offset ) ); |
|
243 } |
|
244 else |
|
245 { |
|
246 timeStamps.Append( TTimeIntervalMicroSeconds32( |
|
247 iCurTimeStamp.Int() ) ); |
|
248 } |
|
249 |
|
250 // Jump to the beginning of next redundancy header |
|
251 streamDecoder.Initialize( const_cast<TUint8*>( seekPtr ), |
|
252 eventCount * KEventBlockLengthInBytes, 0 ); |
|
253 } |
|
254 |
|
255 // Count index of first real event. |
|
256 // Last redundancy header consists of F-bit and PT only. |
|
257 streamDecoder.Initialize( const_cast<TUint8*>( seekPtr ), |
|
258 eventCount * KEventBlockLengthInBytes - |
|
259 KEventBlockLengthInBytes, KBitIndex ); |
|
260 |
|
261 // Decode all events from payload to the event info array. |
|
262 for ( TInt i = 0; i < eventCount; i++ ) |
|
263 { |
|
264 // Decode Event Field |
|
265 TInt eventCode = streamDecoder.Decode( KEventFieldBits ); |
|
266 TChar charRepresentation; |
|
267 |
|
268 if ( KErrNone == ConvertToChar( eventCode, charRepresentation ) ) |
|
269 { |
|
270 iDecodedEventInfo.SetEvent( charRepresentation ); |
|
271 |
|
272 // Decode end bit for final packet |
|
273 iDecodedEventInfo.SetEndBit( streamDecoder.Decode( 1 ) ); |
|
274 |
|
275 // Decode reserved bit |
|
276 streamDecoder.Decode( 1 ); |
|
277 |
|
278 // Decode volume field. |
|
279 iDecodedEventInfo.SetVolume( streamDecoder.Decode( |
|
280 KVolFieldBits ) ); |
|
281 |
|
282 // Decode duration field |
|
283 iDecodedEventInfo.SetDuration( streamDecoder.Decode( |
|
284 KDurationFieldBits ) ); |
|
285 |
|
286 // Set time stamp |
|
287 iDecodedEventInfo.SetTimeStamp( timeStamps[i] ); |
|
288 |
|
289 aEventInfos.Append( iDecodedEventInfo ); |
|
290 } |
|
291 else |
|
292 { |
|
293 DP_DTMF_DECODE( _L( "CDTMFPayloadDecoder::DecodeRedEventPayload" ) ); |
|
294 DP_DTMF_DECODE( _L( "- Not supported event! ") ); |
|
295 } |
|
296 } |
|
297 |
|
298 timeStamps.Reset(); |
|
299 |
|
300 // Delete already played events from the beginning of aEventInfos |
|
301 // array based on time stamp |
|
302 TInt latestRecordedEventInd( iEventArray.Count() - 1 ); |
|
303 |
|
304 if ( 0 <= latestRecordedEventInd ) |
|
305 { |
|
306 while ( aEventInfos.Count() && aEventInfos[0].TimeStamp() |
|
307 <= iEventArray[ latestRecordedEventInd ].TimeStamp() ) |
|
308 { |
|
309 // Redundant event has earlier time stamp than latest played |
|
310 // event we must delete this. |
|
311 aEventInfos.Remove( 0 ); |
|
312 } |
|
313 } |
|
314 |
|
315 // Copy count of accepted events to the end of iEventArray and delete |
|
316 // same count from the beginning of array. Decoder must keep copies of |
|
317 // EventInfos, because PayloadFormatRead may make Reset() for a |
|
318 // aEventInfos Array. |
|
319 for ( TInt j = 0; j < aEventInfos.Count(); j++ ) |
|
320 { |
|
321 iEventArray.Append( aEventInfos[ j ] ); |
|
322 if ( KDTMFDefaultRedundancyCount < iEventArray.Count() ) |
|
323 { |
|
324 iEventArray.Remove( 0 ); |
|
325 } |
|
326 } |
|
327 |
|
328 return KErrNone; |
|
329 } |
|
330 else |
|
331 { |
|
332 return KErrArgument; |
|
333 } |
|
334 } |
|
335 |
|
336 // --------------------------------------------------------------------------- |
|
337 // CDTMFPayloadDecoder::DecodeTonePayload |
|
338 // Decodes tones from Tone Payload Format packet. |
|
339 // Currently only DTMF tones are decoded (first tone). |
|
340 // Format of line event tones are unclear. Are multiple parts containing |
|
341 // line events encoded in one RTP packet or one part per RTP packet. |
|
342 // No proper support at DevSound / AudioServer to play out tone payload. |
|
343 // --------------------------------------------------------------------------- |
|
344 // |
|
345 /* |
|
346 0 1 2 3 |
|
347 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
|
348 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
349 | modulation |T| volume | duration | |
|
350 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
351 |R R R R| frequency |R R R R| frequency | |
|
352 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
353 |R R R R| frequency |R R R R| frequency | |
|
354 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
355 ...... |
|
356 |
|
357 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
358 |R R R R| frequency |R R R R| frequency | |
|
359 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
360 */ |
|
361 TInt CDTMFPayloadDecoder::DecodeTonePayload( CMMFBuffer* aSourceBuffer, |
|
362 RArray<TDTMFTonePayloadInfo>& aToneInfos ) |
|
363 { |
|
364 DP_DTMF_DECODE( _L( "CDTMFPayloadDecoder::DecodeTonePayload" ) ); |
|
365 #ifdef VOIP_TRACE_ENABLED |
|
366 VoipTrace( "%x %x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DECTONEPL, aSourceBuffer ); |
|
367 #endif |
|
368 |
|
369 if ( aSourceBuffer ) |
|
370 { |
|
371 TDes8& dataDes = |
|
372 static_cast<CMMFDataBuffer*>( aSourceBuffer )->Data(); |
|
373 const TUint8* seekPtr = dataDes.Ptr(); |
|
374 |
|
375 TStreamDecoder streamDecoder; |
|
376 |
|
377 streamDecoder.Initialize( const_cast<TUint8*>( seekPtr ), 0, 0 ); |
|
378 |
|
379 // Encode modulation field |
|
380 iDecodedToneInfo.SetModulation( streamDecoder.Decode( |
|
381 KModulationBits ) ); |
|
382 |
|
383 // Encode T bit |
|
384 iDecodedToneInfo.SetTBit( streamDecoder.Decode( 1 ) ); |
|
385 |
|
386 // Encode Volume Field |
|
387 iDecodedToneInfo.SetVolume( streamDecoder.Decode( KVolFieldBits ) ); |
|
388 |
|
389 // Encode Duration Field |
|
390 iDecodedToneInfo.SetDuration( streamDecoder.Decode( |
|
391 KDurationFieldBits ) ); |
|
392 |
|
393 // Encode four R(eserved) bits |
|
394 streamDecoder.Decode( KReservedBits ); |
|
395 |
|
396 // Encode first Frequency Field |
|
397 iDecodedToneInfo.SetLowFrequency( streamDecoder.Decode( |
|
398 KFrequencyBits ) ); |
|
399 |
|
400 // Encode four R(eserved) bits |
|
401 streamDecoder.Decode( KReservedBits ); |
|
402 |
|
403 // Encode second Frequency Field |
|
404 iDecodedToneInfo.SetHighFrequency( streamDecoder.Decode( |
|
405 KFrequencyBits ) ); |
|
406 |
|
407 aToneInfos.Append( iDecodedToneInfo ); |
|
408 |
|
409 return KErrNone; |
|
410 } |
|
411 else |
|
412 { |
|
413 return KErrArgument; |
|
414 } |
|
415 } |
|
416 |
|
417 // --------------------------------------------------------------------------- |
|
418 // CDTMFPayloadDecoder::PayloadFormat |
|
419 // Returns payload format in use. |
|
420 // --------------------------------------------------------------------------- |
|
421 // |
|
422 TDTMFPayloadFormat CDTMFPayloadDecoder::PayloadFormat( ) const |
|
423 { |
|
424 DP_DTMF_DECODE2( _L( "CDTMFPayloadDecoder::PayloadFormat - Format: %d" ), |
|
425 iPayloadFormat ); |
|
426 |
|
427 return iPayloadFormat; |
|
428 } |
|
429 |
|
430 // --------------------------------------------------------------------------- |
|
431 // CDTMFPayloadDecoder::SetPayloadFormat |
|
432 // Sets payload format in use. |
|
433 // --------------------------------------------------------------------------- |
|
434 // |
|
435 TInt CDTMFPayloadDecoder::SetPayloadFormat( |
|
436 TDTMFPayloadFormat aPayloadFormat ) |
|
437 { |
|
438 DP_DTMF_DECODE2( _L( "CDTMFPayloadDecoder::SetPayloadFormat - Format: %d" ), |
|
439 aPayloadFormat ); |
|
440 #ifdef VOIP_TRACE_ENABLED |
|
441 VoipTrace( "%x %x %d", MCC_TRACE, MCC_DTMF_PLF_DEC_SETPLF, aPayloadFormat ); |
|
442 #endif |
|
443 |
|
444 if ( EDTMFPayloadFormatEvent != aPayloadFormat |
|
445 && EDTMFPayloadFormatTone != aPayloadFormat |
|
446 && EDTMFPayloadFormatRedEvents != aPayloadFormat ) |
|
447 { |
|
448 return KErrNotSupported; |
|
449 } |
|
450 else |
|
451 { |
|
452 iPayloadFormat = aPayloadFormat; |
|
453 } |
|
454 |
|
455 return KErrNone; |
|
456 } |
|
457 |
|
458 // --------------------------------------------------------------------------- |
|
459 // CDTMFPayloadDecoder::SetCurTimeStamp |
|
460 // Sets the time stamp of a RTP packet containing payload which is decoded |
|
461 // next. |
|
462 // --------------------------------------------------------------------------- |
|
463 // |
|
464 void CDTMFPayloadDecoder::SetCurTimeStamp( |
|
465 const TTimeIntervalMicroSeconds32& aTimeStamp ) |
|
466 { |
|
467 DP_DTMF_DECODE2( _L( "CDTMFPayloadDecoder::SetCurTimeStamp - TimeStamp: %d" ), |
|
468 aTimeStamp.Int() ); |
|
469 |
|
470 #ifdef VOIP_TRACE_ENABLED |
|
471 VoipTrace( "%x %x %d", MCC_TRACE, MCC_DTMF_PLF_DEC_SETCURTS, aTimeStamp.Int() ); |
|
472 #endif |
|
473 |
|
474 iCurTimeStamp = aTimeStamp; |
|
475 } |
|
476 |
|
477 // --------------------------------------------------------------------------- |
|
478 // CDTMFPayloadDecoder::ConvertToChar |
|
479 // Converts integer presentation used in a payload format to the character. |
|
480 // --------------------------------------------------------------------------- |
|
481 // |
|
482 TInt CDTMFPayloadDecoder::ConvertToChar( TUint aEvent, TChar& aChar ) const |
|
483 { |
|
484 TInt conversionResult( KErrNone ); |
|
485 |
|
486 if ( aEvent <= KMaxEventInteger ) |
|
487 { |
|
488 aChar = TChar( aEvent + '0' ); |
|
489 } |
|
490 else |
|
491 { |
|
492 switch ( aEvent ) |
|
493 { |
|
494 case KEventCodeForAsterisk: |
|
495 aChar = '*'; |
|
496 break; |
|
497 case KEventCodeForHashMark: |
|
498 aChar = '#'; |
|
499 break; |
|
500 case KEventCodeForA: |
|
501 aChar = 'a'; |
|
502 break; |
|
503 case KEventCodeForB: |
|
504 aChar = 'b'; |
|
505 break; |
|
506 case KEventCodeForC: |
|
507 aChar = 'c'; |
|
508 break; |
|
509 case KEventCodeForD: |
|
510 aChar = 'd'; |
|
511 break; |
|
512 default: |
|
513 conversionResult = KErrNotSupported; |
|
514 break; |
|
515 } |
|
516 } |
|
517 |
|
518 return conversionResult; |
|
519 } |
|
520 |
|
521 // End of File |