|
1 // Copyright (c) 2004-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 /** |
|
17 @file |
|
18 @internalComponent |
|
19 @released |
|
20 */ |
|
21 |
|
22 #include <avcframe.h> |
|
23 #include <remconbeareravrcp.h> |
|
24 |
|
25 #include "remconstatusapi.h" |
|
26 #include "remconavrcpstatusconverter.h" |
|
27 |
|
28 /** Factory function. |
|
29 |
|
30 @return Ownership of a new CRemConAvrcpStatusConverter. |
|
31 */ |
|
32 CRemConAvrcpStatusConverter* CRemConAvrcpStatusConverter::NewL() |
|
33 { |
|
34 CRemConAvrcpStatusConverter* self = new(ELeave) CRemConAvrcpStatusConverter; |
|
35 return self; |
|
36 } |
|
37 |
|
38 /** Destructor. |
|
39 */ |
|
40 CRemConAvrcpStatusConverter::~CRemConAvrcpStatusConverter() |
|
41 { |
|
42 } |
|
43 |
|
44 /** Constructor. |
|
45 */ |
|
46 CRemConAvrcpStatusConverter::CRemConAvrcpStatusConverter() |
|
47 { |
|
48 } |
|
49 |
|
50 /** Called to get a converter interface. |
|
51 |
|
52 @param aUid The uid of the desired interface. |
|
53 @return An instance of the desired interface, NULL if |
|
54 one could not be found. |
|
55 */ |
|
56 TAny* CRemConAvrcpStatusConverter::GetInterface(TUid aUid) |
|
57 { |
|
58 TAny* ret = NULL; |
|
59 if ( aUid == TUid::Uid(KRemConConverterInterface1) ) |
|
60 { |
|
61 ret = reinterpret_cast<TAny*>( |
|
62 static_cast<MRemConConverterInterface*>(this) |
|
63 ); |
|
64 } |
|
65 |
|
66 return ret; |
|
67 } |
|
68 |
|
69 /** Decides whether this converter supports this interface. |
|
70 |
|
71 This converter supports only the AVRCP bearer and Status API. |
|
72 This function checks whether the Uids provided match AVRCP and |
|
73 Status. |
|
74 |
|
75 @param aInterfaceData The Uid of the originating RemCon interface. |
|
76 @param aBearerUid The Uid of the bearer this data is destined for. |
|
77 @return Whether this data can be converted. |
|
78 */ |
|
79 TBool CRemConAvrcpStatusConverter::SupportedUids(const TUid& aInterfaceUid, const TUid& aBearerUid) const |
|
80 { |
|
81 return (aInterfaceUid == TUid::Uid(KRemConStatusApiUid) && |
|
82 aBearerUid == TUid::Uid(KRemConBearerAvrcpImplementationUid)); |
|
83 } |
|
84 |
|
85 /** Decides whether this converter supports this interface. |
|
86 |
|
87 This converter supports only the AVRCP bearer. That bearer publishes |
|
88 interface data in the format of an AV/C frame. This function |
|
89 checks that aBearerUid is that of AVRCP, and if so examines the AV/C |
|
90 frame in aInterfaceData to see if it is a supported command. |
|
91 |
|
92 @param aInterfaceData Data in the format of the bearer identified by |
|
93 aBearerUid. |
|
94 @param aBearerUid The Uid of the bearer this data originates from. |
|
95 @return Whether this data can be converted. |
|
96 */ |
|
97 TBool CRemConAvrcpStatusConverter::SupportedInterface(const TDesC8& aInterfaceData, const TUid& aBearerUid) const |
|
98 { |
|
99 TInt supported = EFalse; |
|
100 if(aBearerUid == TUid::Uid(KRemConBearerAvrcpImplementationUid)) |
|
101 { |
|
102 AVC::TOpcode opcode = AVC::EPower; // arbitrary initialisation to avoid compiler warning |
|
103 TRAPD(err, opcode = CAVCFrame::OpcodeL(aInterfaceData)); |
|
104 |
|
105 if ( err == KErrNone |
|
106 && ( opcode == AVC::EUnitInfo || opcode == AVC::ESubunitInfo ) |
|
107 ) |
|
108 { |
|
109 supported = ETrue; |
|
110 } |
|
111 } |
|
112 |
|
113 return supported; |
|
114 } |
|
115 |
|
116 /** Convert data from the API's form (as we're given it by RemCon) to |
|
117 bearer-specific form. |
|
118 |
|
119 We only deal with the AVRCP bearer. This requires us to produce a |
|
120 CAVCFrame. |
|
121 |
|
122 The supported commands are Unit Info and Subunit Info. |
|
123 |
|
124 @param aInterfaceUid The Uid of the originating RemCon interface. |
|
125 @param aOperationId The id of the operation within the interface. |
|
126 @param aData Data in the format defined by the RemCon interface. |
|
127 @param aMsgType Whether this is a command or response. |
|
128 @param aBearerData On return, an AV/C frame representing the operation. |
|
129 */ |
|
130 TInt CRemConAvrcpStatusConverter::InterfaceToBearer(TUid aInterfaceUid, |
|
131 TUint aOperationId, |
|
132 const TDesC8& /*aData*/, |
|
133 TRemConMessageType aMsgType, |
|
134 TDes8& aBearerData) const |
|
135 { |
|
136 __ASSERT_ALWAYS(aInterfaceUid.iUid == KRemConStatusApiUid, CRemConAvrcpStatusConverter::Panic(EStatusConverterWrongInterface)); |
|
137 TInt err = KErrCorrupt; |
|
138 |
|
139 switch(aOperationId) |
|
140 { |
|
141 case ERemConStatusApiUnitInfo: |
|
142 { |
|
143 if(aMsgType == ERemConCommand) |
|
144 { |
|
145 CAVCFrame* frame = NULL; |
|
146 TRAP(err, frame = UnitInfoL()); |
|
147 if(!err) |
|
148 { |
|
149 aBearerData = frame->Data(); |
|
150 err = KErrNone; |
|
151 delete frame; |
|
152 } |
|
153 } |
|
154 else if(aMsgType == ERemConResponse) |
|
155 { |
|
156 // These should be generated within the bearer |
|
157 // as it knows the manufacturer id |
|
158 err = KErrNotSupported; |
|
159 } |
|
160 break; |
|
161 } |
|
162 case ERemConStatusApiSubunitInfo: |
|
163 { |
|
164 if(aMsgType == ERemConCommand) |
|
165 { |
|
166 CAVCFrame* frame = NULL; |
|
167 TRAP(err, frame = SubunitInfoL()); |
|
168 if(!err) |
|
169 { |
|
170 aBearerData = frame->Data(); |
|
171 err = KErrNone; |
|
172 delete frame; |
|
173 } |
|
174 } |
|
175 else if(aMsgType == ERemConResponse) |
|
176 { |
|
177 // These should be generated within the bearer |
|
178 // as it knows the manufacturer id |
|
179 err = KErrNotSupported; |
|
180 } |
|
181 break; |
|
182 } |
|
183 default: |
|
184 { |
|
185 err = KErrNotSupported; |
|
186 break; |
|
187 } |
|
188 } |
|
189 |
|
190 return err; |
|
191 } |
|
192 |
|
193 /** Produce a Unit Info AV/C frame. |
|
194 |
|
195 @return A new AV/C frame representing unit info. |
|
196 @leave System wide error. |
|
197 */ |
|
198 CAVCFrame* CRemConAvrcpStatusConverter::UnitInfoL() |
|
199 { |
|
200 CAVCFrame* frame = CAVCFrame::NewL(AVC::ECommand, AVC::EStatus, AVC::EUnit, AVC::EIgnore); |
|
201 frame->Append(TChar(AVC::EUnitInfo)); |
|
202 frame->Append(TChar(0xff)); |
|
203 frame->Append(TChar(0xff)); |
|
204 frame->Append(TChar(0xff)); |
|
205 frame->Append(TChar(0xff)); |
|
206 frame->Append(TChar(0xff)); |
|
207 return frame; |
|
208 } |
|
209 |
|
210 /** Produce a Subunit Info AV/C frame. |
|
211 |
|
212 @return A new AV/C frame representing subunit info. |
|
213 @leave System wide error. |
|
214 */ |
|
215 CAVCFrame* CRemConAvrcpStatusConverter::SubunitInfoL() |
|
216 { |
|
217 CAVCFrame* frame = CAVCFrame::NewL(AVC::ECommand, AVC::EStatus, AVC::EUnit, AVC::EIgnore); |
|
218 frame->Append(TChar(AVC::ESubunitInfo)); |
|
219 frame->Append(TChar(0x7)); |
|
220 frame->Append(TChar(0xff)); |
|
221 frame->Append(TChar(0xff)); |
|
222 frame->Append(TChar(0xff)); |
|
223 frame->Append(TChar(0xff)); |
|
224 return frame; |
|
225 } |
|
226 |
|
227 /** Convert data from the bearer format to RemCon interface format. |
|
228 |
|
229 We only deal with the Status Api. The supported commands are Unit |
|
230 Info response and Subunit Info response. |
|
231 |
|
232 Support of these commands is mandatory in the targets. In the case |
|
233 where a remote sends us something rubbish, we'll just provide our |
|
234 client with the default info. |
|
235 |
|
236 @param aBearerData An AV/C frame to convert. |
|
237 @param aInterfaceUid On return, the Uid of the RemCon interface. |
|
238 @param aOperationId On return, the id of the operation within the |
|
239 interface. |
|
240 @param aMsgType Whether this is a command or response. |
|
241 @param aData On return, Data in the format defined by the RemCon interface. |
|
242 @return Whether the command was successfully converted. |
|
243 */ |
|
244 TInt CRemConAvrcpStatusConverter::BearerToInterface(const TDesC8& aBearerData, |
|
245 TUid& aInterfaceUid, |
|
246 TUint& aOperationId, |
|
247 TRemConMessageType& aMsgType, |
|
248 TDes8& aData) const |
|
249 { |
|
250 TInt err = KErrCorrupt; |
|
251 |
|
252 switch(aOperationId) |
|
253 { |
|
254 case ERemConStatusApiUnitInfo: |
|
255 { |
|
256 if(aMsgType == ERemConCommand) |
|
257 { |
|
258 // These should be generated within the bearer |
|
259 // as it knows the manufacturer id |
|
260 err = KErrNotSupported; |
|
261 } |
|
262 else if(aMsgType == ERemConResponse) |
|
263 { |
|
264 // We try to parse the data, but if what the remote's sent |
|
265 // us is invalid we'll fill in sensible values later |
|
266 TRAP(err, SetUnitInfoResponseDataL(aBearerData, aData)); |
|
267 aInterfaceUid = TUid::Uid(KRemConStatusApiUid); |
|
268 aOperationId = ERemConStatusApiUnitInfo; |
|
269 |
|
270 if(err == KErrCorrupt) |
|
271 { |
|
272 // The data is set to the correct length in SetUnitInfoResponseDataL |
|
273 // Stick some default data in there |
|
274 SetCommandDataFromInt(aData, KRemConStatusApiUnitOffset, |
|
275 KRemConStatusApiUnitLength, AVC::EID0); |
|
276 |
|
277 SetCommandDataFromInt(aData, KRemConStatusApiUnitTypeOffset, |
|
278 KRemConStatusApiUnitTypeLength, AVC::EPanel); |
|
279 |
|
280 SetCommandDataFromInt(aData, KRemConStatusApiExtendedUnitTypeOffset, |
|
281 KRemConStatusApiExtendedUnitTypeLength, 0); |
|
282 |
|
283 SetCommandDataFromInt(aData, KRemConStatusApiVendorIdOffset, |
|
284 KRemConStatusApiVendorIdLength, KRemConStatusApiDefaultVendorId); |
|
285 |
|
286 err = KErrNone; |
|
287 } |
|
288 } |
|
289 break; |
|
290 } |
|
291 case ERemConStatusApiSubunitInfo: |
|
292 { |
|
293 if(aMsgType == ERemConCommand) |
|
294 { |
|
295 // These should be generated within the bearer |
|
296 // as it knows the manufacturer id |
|
297 err = KErrNotSupported; |
|
298 } |
|
299 else if(aMsgType == ERemConResponse) |
|
300 { |
|
301 // We try to parse the data, but if what the remote's sent |
|
302 // us is invalid we'll fill in sensible values later |
|
303 TRAP(err, SetSubunitInfoResponseDataL(aBearerData, aData)); |
|
304 aInterfaceUid = TUid::Uid(KRemConStatusApiUid); |
|
305 aOperationId = ERemConStatusApiSubunitInfo; |
|
306 |
|
307 if(err == KErrCorrupt) |
|
308 { |
|
309 // Subunit response data varies in length, so the length |
|
310 // set in SetSubunitInfoResponseDataL may be wrong. |
|
311 aData.FillZ(KRemConStatusApiPageLength + KRemConStatusApiExtensionLength + KRemConStatusApiDefaultPageDataLength); |
|
312 |
|
313 // Stick some default data in there |
|
314 SetCommandDataFromInt(aData, KRemConStatusApiPageOffset, |
|
315 KRemConStatusApiPageLength, 0); |
|
316 |
|
317 SetCommandDataFromInt(aData, KRemConStatusApiExtensionOffset, |
|
318 KRemConStatusApiExtensionLength, AVC::EIgnore); |
|
319 |
|
320 SetCommandDataFromInt(aData, KRemConStatusApiPageDataOffset, |
|
321 KRemConStatusApiDefaultPageDataLength, KRemConStatusApiDefaultPageData); |
|
322 |
|
323 err = KErrNone; |
|
324 } |
|
325 } |
|
326 break; |
|
327 } |
|
328 default: |
|
329 { |
|
330 err = KErrNotSupported; |
|
331 break; |
|
332 } |
|
333 } |
|
334 |
|
335 return err; |
|
336 } |
|
337 |
|
338 /** Parses command data from the buffer. |
|
339 |
|
340 @param aCommandData The buffer from which to read the data. |
|
341 @param aVendorId On return, the vendor id |
|
342 @param aUnit On return, the unit |
|
343 @param aUnitType On return, the unit type |
|
344 @param aExtendedUnitType On return, the extended unit type |
|
345 |
|
346 @internalComponent |
|
347 @released |
|
348 */ |
|
349 void CRemConAvrcpStatusConverter::SetUnitInfoResponseDataL(const TDesC8& aBearerData, |
|
350 TDes8& aRemConData) |
|
351 { |
|
352 // AVRCP should pass us a sensible sized buffer! |
|
353 __ASSERT_ALWAYS(aRemConData.MaxLength() >= KUnitInfoResponseLength, CRemConAvrcpStatusConverter::Panic(EAvrcpPassedTooSmallABuffer)); |
|
354 |
|
355 // Get rid of any junk |
|
356 aRemConData.FillZ(KRemConStatusApiUnitLength + KRemConStatusApiUnitTypeLength |
|
357 + KRemConStatusApiExtendedUnitTypeLength |
|
358 + KRemConStatusApiVendorIdLength); |
|
359 |
|
360 // Get unit id if there's enough data for it |
|
361 if(aBearerData.Length() < KUnitIdOffset + KUnitIdLength) |
|
362 { |
|
363 User::Leave(KErrCorrupt); |
|
364 } |
|
365 TInt unit; |
|
366 ReadCommandDataToInt(aBearerData, KUnitIdOffset, KUnitIdLength, unit); |
|
367 unit &= KAVCSubunitIDMask; |
|
368 SetCommandDataFromInt(aRemConData, KRemConStatusApiUnitOffset, |
|
369 KRemConStatusApiUnitLength, unit); |
|
370 |
|
371 // Get unit type (maybe extended) if there's enough data |
|
372 if(aBearerData.Length() < KUnitTypeOffset + KUnitTypeLength) |
|
373 { |
|
374 User::Leave(KErrCorrupt); |
|
375 } |
|
376 TInt unitType; |
|
377 ReadCommandDataToInt(aBearerData, KUnitTypeOffset, KUnitTypeLength, unitType); |
|
378 unitType &= KAVCSubunitTypeMask; |
|
379 unitType >>= KUnitTypeShift; |
|
380 SetCommandDataFromInt(aRemConData, KRemConStatusApiUnitTypeOffset, |
|
381 KRemConStatusApiUnitTypeLength, unitType); |
|
382 |
|
383 TInt unitTypeExtend = 0; |
|
384 TInt vendorIdOffset = KVendorIdBaseOffset; |
|
385 if(unitType == KUnitTypeExtend) |
|
386 { |
|
387 // Extended unit type. VendorId is offset by 1 |
|
388 vendorIdOffset++; |
|
389 |
|
390 // Read the next byte if it's there |
|
391 if(aBearerData.Length() < KUnitTypeExtendOffset + 1) |
|
392 { |
|
393 User::Leave(KErrCorrupt); |
|
394 } |
|
395 ReadCommandDataToInt(aBearerData, KUnitTypeExtendOffset, 1, unitTypeExtend); |
|
396 unitTypeExtend <<= 8; |
|
397 |
|
398 // Double extended unit type. |
|
399 if(unitTypeExtend == KUnitTypeExtendExtend) |
|
400 { |
|
401 // VendorId is offset by 1 |
|
402 vendorIdOffset++; |
|
403 |
|
404 // Read the next byte |
|
405 TInt unitTypeExtendExtend = 0; |
|
406 if(aBearerData.Length() < KUnitTypeExtendExtendOffset + 1) |
|
407 { |
|
408 User::Leave(KErrCorrupt); |
|
409 } |
|
410 ReadCommandDataToInt(aBearerData, KUnitTypeExtendExtendOffset, 1, |
|
411 unitTypeExtendExtend); |
|
412 unitTypeExtend |= unitTypeExtendExtend; |
|
413 } |
|
414 |
|
415 SetCommandDataFromInt(aRemConData, KRemConStatusApiExtendedUnitTypeOffset, |
|
416 KRemConStatusApiExtendedUnitTypeLength, unitTypeExtend); |
|
417 } |
|
418 |
|
419 // Get vendor id |
|
420 if(aBearerData.Length() < vendorIdOffset + KVendorIdLength) |
|
421 { |
|
422 User::Leave(KErrCorrupt); |
|
423 } |
|
424 TInt vendorId; |
|
425 ReadCommandDataToInt(aBearerData, vendorIdOffset, KVendorIdLength, vendorId); |
|
426 SetCommandDataFromInt(aRemConData, KRemConStatusApiVendorIdOffset, |
|
427 KRemConStatusApiVendorIdLength, vendorId); |
|
428 } |
|
429 |
|
430 /** Parses command data from the buffer. |
|
431 |
|
432 @param aCommandData The buffer from which to read the data. |
|
433 @param aPage On return, the page |
|
434 @param aExtension On return, the extension |
|
435 @param aPageData On return, the page data |
|
436 |
|
437 @internalComponent |
|
438 @released |
|
439 */ |
|
440 void CRemConAvrcpStatusConverter::SetSubunitInfoResponseDataL(const TDesC8& aBearerData, |
|
441 TDes8& aRemConData) |
|
442 { |
|
443 // AVRCP should pass us a sensible sized buffer! |
|
444 __ASSERT_ALWAYS(aRemConData.MaxLength() >= KUnitInfoResponseLength, CRemConAvrcpStatusConverter::Panic(EAvrcpPassedTooSmallABuffer)); |
|
445 |
|
446 CAVCFrame* frame = CAVCFrame::NewL(aBearerData, AVC::EResponse); //Qualified |
|
447 CleanupStack::PushL(frame); |
|
448 TPtrC8 ptr = frame->Data(); |
|
449 |
|
450 // Work out how long a buffer we need for the RemCon data. |
|
451 // This is KRemConStatusApiPageLength + KRemConStatusApiExtensionLength |
|
452 // + the length of the page data. |
|
453 // We can work out the length of the page data from the frame - |
|
454 // it's the remainder of the frame after KSubunitPageDataOffset. |
|
455 // This gives us: |
|
456 TInt remConDataLen = KRemConStatusApiPageLength |
|
457 + KRemConStatusApiPageLength |
|
458 + (ptr.Length() - KSubunitPageDataOffset); |
|
459 |
|
460 if(aRemConData.MaxLength() < remConDataLen) |
|
461 { |
|
462 User::Leave(KErrCorrupt); |
|
463 } |
|
464 |
|
465 // Get rid of any junk |
|
466 aRemConData.FillZ(remConDataLen); |
|
467 |
|
468 // Get page |
|
469 if(aBearerData.Length() < KSubunitPageOffset + KSubunitPageLength) |
|
470 { |
|
471 User::Leave(KErrCorrupt); |
|
472 } |
|
473 TInt page; |
|
474 ReadCommandDataToInt(aBearerData, KSubunitPageOffset, KSubunitPageLength, page); |
|
475 page &= KSubunitPageMask; |
|
476 SetCommandDataFromInt(aRemConData, KRemConStatusApiPageOffset, |
|
477 KRemConStatusApiPageLength, page); |
|
478 |
|
479 // Get extension code |
|
480 if(aBearerData.Length() < KSubunitExtensionOffset + KSubunitExtensionLength) |
|
481 { |
|
482 User::Leave(KErrCorrupt); |
|
483 } |
|
484 TInt extensionCode; |
|
485 ReadCommandDataToInt(aBearerData, KSubunitExtensionOffset, KSubunitExtensionLength, |
|
486 extensionCode); |
|
487 extensionCode &= KSubunitExtensionMask; |
|
488 SetCommandDataFromInt(aRemConData, KRemConStatusApiExtensionOffset, |
|
489 KRemConStatusApiExtensionLength, extensionCode); |
|
490 |
|
491 // Get page data |
|
492 TPtrC8 pageDataPtr = aBearerData.Mid(KSubunitPageDataOffset); |
|
493 aRemConData.Replace(KRemConStatusApiPageDataOffset, pageDataPtr.Length(), pageDataPtr); |
|
494 |
|
495 CleanupStack::PopAndDestroy(frame); |
|
496 } |
|
497 |
|
498 /** Reads command data from the buffer to an int. |
|
499 |
|
500 @param aCommandData The buffer from which to read the data. |
|
501 @param aOffset The offset within aCommandData read from. |
|
502 @param aLength The length of data to read. This must not be |
|
503 more than 4. |
|
504 @param aValue On return, the value of the specified data section. |
|
505 |
|
506 @internalComponent |
|
507 @released |
|
508 */ |
|
509 void CRemConAvrcpStatusConverter::ReadCommandDataToInt(const TDesC8& aCommandData, |
|
510 TInt aOffset, TInt aLength, TInt& aValue) |
|
511 { |
|
512 __ASSERT_DEBUG(aLength <= 4, CRemConAvrcpStatusConverter::Panic(EStatusConverterDataTooShort)); |
|
513 |
|
514 aValue = 0; |
|
515 |
|
516 for(TInt i = 0 ; i < aLength; i++) |
|
517 { |
|
518 aValue |= aCommandData[aOffset+i]<<(8*i); |
|
519 } |
|
520 } |
|
521 |
|
522 /** Set the command data. This overwrites the current |
|
523 contents of the data buffer. |
|
524 |
|
525 @param aCommandData The buffer in which to set the data. |
|
526 @param aOffset The offset within aCommandData to set the data. |
|
527 @param aLength The length of data to replace. |
|
528 @param aValue The new value for the replaced data. |
|
529 */ |
|
530 void CRemConAvrcpStatusConverter::SetCommandDataFromInt(TDes8& aCommandData, |
|
531 TInt aOffset, TInt aLength, TInt aValue) |
|
532 { |
|
533 __ASSERT_DEBUG(aLength <= 4, CRemConAvrcpStatusConverter::Panic(EStatusConverterDataTooShort)); |
|
534 |
|
535 for(TInt i = 0; i < aLength; i++) |
|
536 { |
|
537 aCommandData[aOffset+i] = aValue >> (8*i); |
|
538 } |
|
539 } |
|
540 |
|
541 /** Utility Status Converter panic function. |
|
542 |
|
543 @param aPanic The panic number. |
|
544 */ |
|
545 void CRemConAvrcpStatusConverter::Panic(TStatusConverterPanic aPanic) |
|
546 { |
|
547 User::Panic(KStatusConverterPanicName, aPanic); |
|
548 } |
|
549 |
|
550 // |
|
551 // End of file |