|
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 |
|
18 /** |
|
19 @file |
|
20 @internalComponent |
|
21 @released |
|
22 */ |
|
23 #include <avcframe.h> |
|
24 #include <e32base.h> |
|
25 #include <remcon/remconbearerobserver.h> |
|
26 #include <remcon/remconconverterplugin.h> |
|
27 #include <remcon/messagetype.h> |
|
28 #include <remconbeareravrcp.h> |
|
29 |
|
30 #include <absolutevolumeapi.h> |
|
31 #include <absolutevolumeutils.h> |
|
32 #include <remcon/avrcpspec.h> |
|
33 #include "controlcommand.h" |
|
34 #include "avrcpcommandframer.h" |
|
35 #include "avrcpfragmenter.h" |
|
36 #include "avrcpinternalinterface.h" |
|
37 #include "avrcpipc.h" |
|
38 #include "avrcplog.h" |
|
39 #include "avrcputils.h" |
|
40 #include "avrcpincomingcommandhandler.h" |
|
41 #include "avrcp.h" |
|
42 #include "mediabrowse.h" |
|
43 #include "mediainformation.h" |
|
44 #include "nowplaying.h" |
|
45 #include "playerinformation.h" |
|
46 #include "remconbattery.h" |
|
47 #include "remcongroupnavigation.h" |
|
48 |
|
49 //--------------------------------------------------------------------- |
|
50 // Outgoing command construction |
|
51 //--------------------------------------------------------------------- |
|
52 |
|
53 /** Factory function. |
|
54 |
|
55 @param aInterfaceUid The RemCon interface uid of this command. |
|
56 @param aCommand The operation id of this command within the interface defined |
|
57 by aInterface Uid. |
|
58 @param aRemConId The RemCon transaction label. |
|
59 @param aTransactionLabel The AVCTP transaction label. |
|
60 @param aCommandData The RemCon command data associated with this command. |
|
61 @param aIsClick Whether this command is a button click (ie RemCon believes |
|
62 that this and the other part of the click constitute one |
|
63 command. |
|
64 @param aAddr The bluetooth address to send this command to. |
|
65 @return A fully constructed CControlCommand. |
|
66 @leave System wide error codes. |
|
67 */ |
|
68 CControlCommand* CControlCommand::NewL(TUid aInterfaceUid, |
|
69 TUint aCommand, |
|
70 TUint aRemConId, |
|
71 SymbianAvctp::TTransactionLabel aTransactionLabel, |
|
72 RBuf8& aCommandData, |
|
73 TBool aIsClick, |
|
74 const TBTDevAddr& aAddr, |
|
75 TBool aKnownToBearer) |
|
76 { |
|
77 LOG_STATIC_FUNC |
|
78 CControlCommand* command = new (ELeave) CControlCommand(aInterfaceUid, aCommand, |
|
79 aRemConId, aTransactionLabel, aCommandData, aIsClick, aAddr, aKnownToBearer); |
|
80 CleanupStack::PushL(command); |
|
81 command->ConstructL(); |
|
82 CleanupStack::Pop(command); |
|
83 return command; |
|
84 } |
|
85 |
|
86 /** Constructor. |
|
87 |
|
88 @param aInterfaceUid The RemCon interface uid of this command. |
|
89 @param aCommand The operation id of this command within the interface defined |
|
90 by aInterface Uid. |
|
91 @param aRemConId The RemCon transaction label. |
|
92 @param aTransactionLabel The AVCTP transaction label. |
|
93 @param aCommandData The RemCon command data associated with this command. |
|
94 @param aIsClick Whether this command is a button click (ie RemCon believes |
|
95 that this and the other part of the click constitute one |
|
96 command. |
|
97 @param aAddr The bluetooth address to send this command to. |
|
98 @return A constructed CControlCommand. |
|
99 @leave System wide error codes. |
|
100 */ |
|
101 CControlCommand::CControlCommand(TUid aInterfaceUid, |
|
102 TUint aCommand, |
|
103 TUint aRemConId, |
|
104 SymbianAvctp::TTransactionLabel aTransactionLabel, |
|
105 RBuf8& aCommandData, |
|
106 TBool aIsClick, |
|
107 const TBTDevAddr& aAddr, |
|
108 TBool aKnownToBearer) |
|
109 : CAvrcpCommand(aRemConId, aTransactionLabel, aAddr) |
|
110 { |
|
111 LOG_FUNC |
|
112 |
|
113 iIsClick = aIsClick; |
|
114 iInterfaceUid = aInterfaceUid; |
|
115 iOperationId = aCommand; |
|
116 iKnownToBearer = aKnownToBearer; |
|
117 |
|
118 iCommandData.Assign(aCommandData); |
|
119 aCommandData.Assign(NULL); |
|
120 iPlayerInfoManager = NULL; |
|
121 } |
|
122 |
|
123 //--------------------------------------------------------------------- |
|
124 // Incoming command construction |
|
125 //--------------------------------------------------------------------- |
|
126 |
|
127 /** Factory function. |
|
128 |
|
129 @param aMessageInformation A buffer containing AV/C frame this command is to represent. |
|
130 @param aRemConId The RemCon transaction label. |
|
131 @param aTransLabel The AVCTP transaction label. |
|
132 @param aAddr The bluetooth address to send the response to. |
|
133 @param aClientId The RemCon client that should receive this command |
|
134 @return A fully constructed CControlCommand. |
|
135 @leave System wide error codes. |
|
136 */ |
|
137 CControlCommand* CControlCommand::NewL(CAVCFrame* aFrame, |
|
138 TUint aRemConId, |
|
139 SymbianAvctp::TTransactionLabel aTransLabel, |
|
140 const TBTDevAddr& aAddr, |
|
141 const TRemConClientId& aClientId, |
|
142 CAvrcpPlayerInfoManager* aPlayerInfoManager) |
|
143 { |
|
144 LOG_STATIC_FUNC |
|
145 CControlCommand* command = new(ELeave)CControlCommand(aFrame, aRemConId, aTransLabel, aAddr, aClientId, aPlayerInfoManager); |
|
146 CleanupStack::PushL(command); |
|
147 command->ConstructL(); |
|
148 CleanupStack::Pop(command); |
|
149 return command; |
|
150 } |
|
151 |
|
152 /** Constructor. |
|
153 |
|
154 @param aRemConId The RemCon transaction label. |
|
155 @param aTransLabel The AVCTP transaction label. |
|
156 @param aAddr The bluetooth address to send the response to. |
|
157 @param aClientId The RemCon client that should receive this command |
|
158 @return A partially constructed CControlCommand. |
|
159 @leave System wide error codes. |
|
160 */ |
|
161 CControlCommand::CControlCommand(CAVCFrame* aFrame, |
|
162 TUint aRemConId, |
|
163 SymbianAvctp::TTransactionLabel aTransLabel, |
|
164 const TBTDevAddr& aAddr, |
|
165 const TRemConClientId& aClientId, |
|
166 CAvrcpPlayerInfoManager* aPlayerInfoManager) |
|
167 : CAvrcpCommand(aRemConId, aTransLabel, aAddr) |
|
168 , iFrame(aFrame) |
|
169 , iClientId(aClientId) |
|
170 { |
|
171 LOG_FUNC |
|
172 |
|
173 iIsClick = ETrue; // Assume click until we know otherwise |
|
174 iPlayerInfoManager = aPlayerInfoManager; |
|
175 } |
|
176 |
|
177 //--------------------------------------------------------------------- |
|
178 // Generic construction/destruction |
|
179 //--------------------------------------------------------------------- |
|
180 |
|
181 /** Destructor. |
|
182 */ |
|
183 CControlCommand::~CControlCommand() |
|
184 { |
|
185 LOG_FUNC |
|
186 __ASSERT_DEBUG(iUsers == 0, AvrcpUtils::Panic(EAvrcpCommandStillInUse)); |
|
187 __ASSERT_ALWAYS(!iHandlingLink.IsQueued(), AvrcpUtils::Panic(EAvrcpCommandStillQueuedForHandling)); |
|
188 __ASSERT_ALWAYS(!iReadyLink.IsQueued(), AvrcpUtils::Panic(EAvrcpCommandStillQueuedAsReady)); |
|
189 __ASSERT_ALWAYS(!iSendLink.IsQueued(), AvrcpUtils::Panic(EAvrcpCommandStillQueuedForSending)); |
|
190 delete iFrame; |
|
191 iCommandData.Close(); |
|
192 delete iTimerEntry; |
|
193 delete iTimerExpiryInfo; |
|
194 } |
|
195 |
|
196 /** Second phase construction. |
|
197 |
|
198 @leave System wide error codes. |
|
199 */ |
|
200 void CControlCommand::ConstructL() |
|
201 { |
|
202 LOG_FUNC |
|
203 |
|
204 // Allocate these now so we know we have the memory. Info is |
|
205 // irrelevant as we won't add to the timer's queue without |
|
206 // setting the true info. |
|
207 TCallBack callback(DummyCallback, NULL); |
|
208 iTimerEntry = new(ELeave)TDeltaTimerEntry(callback); |
|
209 iTimerExpiryInfo = new(ELeave)TAvrcpTimerExpiryInfo(NULL, *this); |
|
210 } |
|
211 |
|
212 //------------------------------------------------------------------------------------ |
|
213 // From MRcpTimerNotify |
|
214 //------------------------------------------------------------------------------------ |
|
215 |
|
216 /** Get the timer entry. |
|
217 |
|
218 @return Timer entry. |
|
219 */ |
|
220 TDeltaTimerEntry* CControlCommand::TimerEntry() |
|
221 { |
|
222 return iTimerEntry; |
|
223 } |
|
224 |
|
225 /** Get the timer expiry info. |
|
226 |
|
227 @return Timer expiry info. |
|
228 */ |
|
229 TAvrcpTimerExpiryInfo* CControlCommand::TimerExpiryInfo() |
|
230 { |
|
231 return iTimerExpiryInfo; |
|
232 } |
|
233 |
|
234 /** Remove this command's timer entry from the queue. |
|
235 |
|
236 @param aTimer The timer queue to remove this from. |
|
237 */ |
|
238 void CControlCommand::CancelTimer(CDeltaTimer& aTimer) |
|
239 { |
|
240 LOG_FUNC |
|
241 |
|
242 aTimer.Remove(*iTimerEntry); |
|
243 } |
|
244 |
|
245 //------------------------------------------------------------------------------------ |
|
246 // Called by bearer |
|
247 //------------------------------------------------------------------------------------ |
|
248 |
|
249 const TRemConClientId& CControlCommand::ClientId() const |
|
250 { |
|
251 return iClientId; |
|
252 } |
|
253 //------------------------------------------------------------------------------------ |
|
254 // Called by handlers |
|
255 //------------------------------------------------------------------------------------ |
|
256 |
|
257 /** Creates iFrame. |
|
258 |
|
259 This function must be called between creating this command and using it. |
|
260 |
|
261 @param aInterfaceUid The RemCon interface this command came from. |
|
262 @param aCommand The command id within the interface identified by aInterfaceUid. |
|
263 @param aCommandData Data supplied with this command by RemCon. The format of this |
|
264 data is defined by RemCon and is dependent on aInterfaceUid and |
|
265 aCommand. |
|
266 @leave System wide error code if parsing could not complete. |
|
267 */ |
|
268 void CControlCommand::ProcessOutgoingCommandL(MRemConBearerObserver& aObserver) |
|
269 { |
|
270 LOG_FUNC |
|
271 |
|
272 switch(iInterfaceUid.iUid) |
|
273 { |
|
274 //Process the absolute volume controller api |
|
275 case KRemConAbsoluteVolumeControllerApiUid: |
|
276 { |
|
277 switch (iOperationId) |
|
278 { |
|
279 //Registers absolute volume changed |
|
280 case KRemConAbsoluteVolumeNotification: |
|
281 { |
|
282 iFrame = AvrcpCommandFramer::NotifyVolumeChangeCommandL(); |
|
283 break; |
|
284 } |
|
285 //Sets absolute volume. |
|
286 case KRemConSetAbsoluteVolume: |
|
287 { |
|
288 //Gets the absolute volume to be set. |
|
289 RRemConAbsoluteVolumeRequest setAbsVol; |
|
290 CleanupClosePushL(setAbsVol); |
|
291 setAbsVol.ReadL(iCommandData); |
|
292 |
|
293 __ASSERT_ALWAYS(setAbsVol.iVolume <= setAbsVol.iMaxVolume, |
|
294 AvrcpUtils::Panic(EAvrcpVolumeBeyondMaxVolume)); |
|
295 |
|
296 TUint8 absVol = KAvrcpMaxAbsoluteVolume * setAbsVol.iVolume / setAbsVol.iMaxVolume; |
|
297 iFrame = AvrcpCommandFramer::SetAbsoluteVolumeCommandL(absVol); |
|
298 CleanupStack::PopAndDestroy(&setAbsVol); |
|
299 break; |
|
300 } |
|
301 default: |
|
302 { |
|
303 User::Leave(KErrNotSupported); |
|
304 } |
|
305 |
|
306 } |
|
307 break; |
|
308 } |
|
309 case KRemConCoreApiUid: |
|
310 { |
|
311 // Default interface - all commands are passthrough |
|
312 AVCPanel::TOperationId avrcpOp; |
|
313 |
|
314 if((RemConToAvrcpOperation(iOperationId, avrcpOp) != KErrNone) || |
|
315 (iCommandData.Length() < KRemConCoreApiButtonDataLength)) |
|
316 { |
|
317 User::Leave(KErrCorrupt); |
|
318 } |
|
319 else |
|
320 { |
|
321 TInt remConButtonAct; |
|
322 AvrcpUtils::ReadCommandDataToInt(iCommandData, |
|
323 KRemConCoreApiCommandDataOffset + KRemConCoreApiButtonDataOffset, |
|
324 KRemConCoreApiButtonDataLength, remConButtonAct); |
|
325 |
|
326 AVCPanel::TButtonAction buttonAct = (remConButtonAct == ERemConCoreApiButtonPress) ? |
|
327 AVCPanel::EButtonPress : AVCPanel::EButtonRelease; |
|
328 |
|
329 iFrame = AvrcpCommandFramer::PassthroughL(avrcpOp, buttonAct); |
|
330 if(iIsClick) |
|
331 { |
|
332 // restore our mangled command data |
|
333 AvrcpUtils::SetCommandDataFromInt(iCommandData, |
|
334 KRemConCoreApiCommandDataOffset + KRemConCoreApiButtonDataOffset, |
|
335 KRemConCoreApiButtonDataLength, ERemConCoreApiButtonClick); |
|
336 } |
|
337 } |
|
338 break; |
|
339 } |
|
340 default: |
|
341 { |
|
342 RBuf8 buf; |
|
343 buf.CreateMaxL(KAVCFrameMaxLength); |
|
344 User::LeaveIfError(aObserver.InterfaceToBearer(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
345 iInterfaceUid, iOperationId, iCommandData, ERemConCommand, buf)); |
|
346 |
|
347 CleanupClosePushL(buf); |
|
348 iFrame = CAVCFrame::NewL(buf, AVC::ECommand); |
|
349 CleanupStack::PopAndDestroy(&buf); |
|
350 break; |
|
351 } |
|
352 }; |
|
353 } |
|
354 |
|
355 /** Fills in command info from iFrame. |
|
356 |
|
357 This must be called by the command handler before handling this |
|
358 command. |
|
359 |
|
360 This functions sets iInterfaceUid, iOperationId and iCommandData |
|
361 to the correct values according to iFrame. The format of iCommandData |
|
362 is defined by RemCon and is dependent on iInterfaceUid and iOperationId. |
|
363 |
|
364 @return KErrNone If the frame has been parsed successfully. |
|
365 @return KErrNotSupported This frame represents a command for which a |
|
366 RemCon converter or client side interface |
|
367 cannot be found. |
|
368 @return KErrAvrcpInvalidCType The CType specified in this frame is invalid. |
|
369 @return KErrAvrcpMetadataInvalidCommand The AVRCP command is invalid. |
|
370 @return KErrAvrcpMetadataInvalidParameter The AVRCP parameter is invalid. |
|
371 @return KErrAvrcpMetadataParameterNotFound The AVRCP parameter was not found. |
|
372 @return KErrAvrcpMetadataInternalError An AVRCP internal error occurred (such as out-of-memory, |
|
373 or an inter-process communication error) |
|
374 @return KErrCorrupt If the frame is corrupted(e.g invalid Operation Id). |
|
375 @return System wide error code. |
|
376 */ |
|
377 TInt CControlCommand::ParseIncomingCommandL(MRemConBearerObserver& aObserver, CAVRCPFragmenter& aFragmenter) |
|
378 { |
|
379 LOG_FUNC |
|
380 TInt err = KErrNotSupported; |
|
381 |
|
382 switch(iFrame->Type()) |
|
383 { |
|
384 // check it isn't a reponse |
|
385 case AVC::ENotImplemented: |
|
386 case AVC::EAccepted: |
|
387 case AVC::ERejected: |
|
388 case AVC::EInTransition: |
|
389 case AVC::EImplemented: |
|
390 case AVC::EChanged: |
|
391 case AVC::EInterim: |
|
392 case 0x0E: // not given a enum for SC reasons; reserved response code in spec |
|
393 { |
|
394 // We were told this was a command, can't go using response |
|
395 // CTypes here matey |
|
396 err = KErrAvrcpInvalidCType; |
|
397 break; |
|
398 } |
|
399 case AVC::EGeneralEnquiry: |
|
400 case AVC::ESpecificEnquiry: |
|
401 { |
|
402 err = KErrNotSupported; |
|
403 break; |
|
404 } |
|
405 default: |
|
406 if (iFrame->Opcode() == AVC::EVendorDependent) |
|
407 { |
|
408 err = ParseIncomingVendorCommandL(aObserver, aFragmenter); |
|
409 } |
|
410 |
|
411 else |
|
412 { |
|
413 // give off to the regular processor |
|
414 err = ParseIncomingKnownOpcodeL(aObserver); |
|
415 } |
|
416 break; |
|
417 }; |
|
418 |
|
419 |
|
420 return err; |
|
421 } |
|
422 |
|
423 /** Processes an incoming response. |
|
424 |
|
425 This function may not fail. We always need to generate something |
|
426 to RemCon. |
|
427 |
|
428 @param aObserver Observer to use for retrieving converter. |
|
429 @param aFrame The AV/C frame containing the response. |
|
430 */ |
|
431 TInt CControlCommand::ParseIncomingResponse(MRemConBearerObserver& aObserver, const CAVCFrame& aFrame) |
|
432 { |
|
433 LOG_FUNC |
|
434 TInt error = KErrNone; |
|
435 |
|
436 // Compare Opcode with that of the sent frame rather than the |
|
437 // received one because we trust that more. Should be the same |
|
438 // as this is matched by AVCTP transaction label, but who knows |
|
439 // what those illicit remote devices could be up to. |
|
440 if(iFrame->Opcode() == AVC::EPassThrough) |
|
441 { |
|
442 switch(aFrame.Type()) |
|
443 { |
|
444 case AVC::EAccepted: |
|
445 { |
|
446 InsertCoreResult(KErrNone); |
|
447 break; |
|
448 } |
|
449 case AVC::ENotImplemented: |
|
450 { |
|
451 InsertCoreResult(KErrNotSupported); |
|
452 break; |
|
453 } |
|
454 default: |
|
455 { |
|
456 InsertCoreResult(KErrGeneral); |
|
457 break; |
|
458 } |
|
459 } |
|
460 } |
|
461 else if (iFrame->Opcode() == AVC::EVendorDependent) |
|
462 { |
|
463 TPtrC8 payloadData; |
|
464 AVC::TAVCVendorId vID; |
|
465 //Get the PDU ID with that of the sent frame rather than the received one, |
|
466 //the reason is the same to above comments. |
|
467 payloadData.Set(CAVCVendorDependentCommand::GetPayloadAndVID(*iFrame, vID)); |
|
468 if (vID == KBluetoothSIGVendorId) |
|
469 { |
|
470 TMetadataTransferPDUID metadataPDUID = MetadataTransferParser::GetPDUID(payloadData); |
|
471 switch ( metadataPDUID ) |
|
472 { |
|
473 case ESetAbsoluteVolume://Response for setting absolute volume. |
|
474 { |
|
475 error = SetSetAbsoluteVolumeResult(aFrame); |
|
476 break; |
|
477 } |
|
478 case ERegisterNotification: |
|
479 { |
|
480 //Get notify event ID with the sent frame rather than the received one |
|
481 //because there is a big possibility that the received one is an error response, e.g. rejected,notimplemented. |
|
482 //In order to make sure this is an absolute volume response even if the response is an error response, |
|
483 //we have to use the sent frame, and then we can process absolute volume specifically. |
|
484 TMetadataTransferNotifyEventID eventID = MetadataTransferParser::GetNotifyEventID(payloadData); |
|
485 |
|
486 __ASSERT_ALWAYS(eventID == ERegisterNotificationVolumeChanged, |
|
487 AvrcpUtils::Panic(EAvrcpInvalidEventId)); |
|
488 |
|
489 if (eventID == ERegisterNotificationVolumeChanged) |
|
490 { |
|
491 error = SetNotifyVolumeChangeResult(aFrame); |
|
492 } |
|
493 break; |
|
494 } |
|
495 default: |
|
496 { |
|
497 // Should never hit here |
|
498 AvrcpUtils::Panic(EAvrcpResponseToUnknownCommand); |
|
499 break; |
|
500 } |
|
501 } |
|
502 } |
|
503 else |
|
504 { |
|
505 ParseIncomingUnknownResponse(aObserver, aFrame); |
|
506 } |
|
507 } |
|
508 else |
|
509 { |
|
510 ParseIncomingUnknownResponse(aObserver, aFrame); |
|
511 } |
|
512 |
|
513 return error; |
|
514 } |
|
515 |
|
516 /** Processes an outgoing response. |
|
517 |
|
518 This should only be called for vendor dependent commands as |
|
519 we respond to passthrough commands internally. |
|
520 |
|
521 @param aObserver Observer to use for retrieving converter. |
|
522 @param aFrame The command data for the response. |
|
523 */ |
|
524 TInt CControlCommand::ProcessOutgoingResponse(MRemConBearerObserver& aObserver, |
|
525 // TRemConMessageType aMessageType, |
|
526 RBuf8& aResponseData, |
|
527 CAVRCPFragmenter& aFragmenter) |
|
528 { |
|
529 TRAPD(err, DoProcessOutgoingResponseL(aObserver,aResponseData, aFragmenter)); |
|
530 return err; |
|
531 } |
|
532 |
|
533 void CControlCommand::DoProcessOutgoingResponseL(MRemConBearerObserver& aObserver, |
|
534 RBuf8& aResponseData, |
|
535 CAVRCPFragmenter& aFragmenter) |
|
536 { |
|
537 LOG_FUNC |
|
538 |
|
539 // Payload size may be increased in GenerateMetadataResponsePayload |
|
540 // if there's a very large response which needs fragmenting |
|
541 RBuf8 payload; |
|
542 payload.CreateL(KAVCFrameMaxLength); |
|
543 CleanupClosePushL(payload); |
|
544 |
|
545 if(( iInterfaceUid.iUid == KRemConMediaInformationApiUid ) |
|
546 || ( iInterfaceUid.iUid == KRemConPlayerInformationUid ) |
|
547 || ( iInterfaceUid.iUid == KRemConAbsoluteVolumeTargetApiUid ) |
|
548 || ( iInterfaceUid.iUid == KRemConNowPlayingApiUid ) |
|
549 || ( iInterfaceUid.iUid == KUidAvrcpInternalInterface)) |
|
550 { |
|
551 // metadata |
|
552 // "this" is the command for which the response lurks in aCommandData |
|
553 // GenerateMetadataResponsePayload() MUST set PDU id, fragmentation stauts |
|
554 // and paramlen (4 bytes total) - check this in ASSERT_DEBUG |
|
555 User::LeaveIfError(GenerateMetadataResponsePayload(aObserver, payload, aResponseData)); |
|
556 __ASSERT_DEBUG(payload.Length() >= KAVRCPMinVendorDependentResponseLen, AvrcpUtils::Panic(EAvrcpFunnyLengthData)); |
|
557 aResponseData.Close(); |
|
558 |
|
559 if (payload.Length() > KAVCMaxVendorDependentPayload) |
|
560 { |
|
561 // Fragment response (in payload) and queue fragments ready |
|
562 // for sending when CT sends a CONTINUE request. If any other |
|
563 // request is received (other than pass-through) then throw |
|
564 // away our fragmented packet, as the CT has aborted. |
|
565 aFragmenter.AssignPayload(payload); |
|
566 payload.Assign(NULL); |
|
567 payload.Close(); |
|
568 |
|
569 // Re-allocate this back to a sensible size |
|
570 // from the much larger size, which has now been |
|
571 // assigned to fragmenter (avoids copying payload) |
|
572 payload.CreateL(KAVCFrameMaxLength); |
|
573 payload.Append(aFragmenter.GetNextFragmentHeader()); |
|
574 payload.Append(aFragmenter.GetNextFragment()); |
|
575 } |
|
576 |
|
577 CAVCFrame* frame = CAVCVendorDependentResponse::NewL(KBluetoothSIGVendorId); |
|
578 frame->Append(payload); |
|
579 frame->SetType(iFrame->Type()); |
|
580 delete iFrame; |
|
581 iFrame = frame; |
|
582 } |
|
583 else |
|
584 { |
|
585 User::LeaveIfError(aObserver.InterfaceToBearer(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
586 iInterfaceUid, iOperationId, |
|
587 aResponseData, /*ERemConCommand*/ERemConResponse, payload)); |
|
588 aResponseData.Close(); |
|
589 CAVCFrame* frame = CAVCFrame::NewL(payload, AVC::EResponse); |
|
590 delete iFrame; |
|
591 iFrame = frame; |
|
592 } |
|
593 |
|
594 CleanupStack::PopAndDestroy(&payload); |
|
595 } |
|
596 |
|
597 /** Set the response type in the AV/C frame. |
|
598 |
|
599 @param aErr The result of processing the operation. KErrNone if |
|
600 successful. KErrNotsupported if this operation is not |
|
601 implemented, eg because no converter was found. |
|
602 */ |
|
603 void CControlCommand::SetResponseType(TInt aErr) |
|
604 { |
|
605 LOG_FUNC |
|
606 AVC::TCType cType = iFrame->Type(); |
|
607 switch(aErr) |
|
608 { |
|
609 case KErrNone: |
|
610 case KErrCompletion: |
|
611 if (cType == AVC::EControl) |
|
612 { |
|
613 iFrame->SetType(AVC::EAccepted); |
|
614 } |
|
615 else if (cType == AVC::ENotify) |
|
616 { |
|
617 iFrame->SetType(AVC::EInterim); |
|
618 } |
|
619 else if (cType == AVC::EInterim) |
|
620 { |
|
621 iFrame->SetType(AVC::EChanged); |
|
622 } |
|
623 else if (cType == AVC::EStatus) |
|
624 { |
|
625 iFrame->SetType(AVC::EStable); |
|
626 } |
|
627 else |
|
628 { |
|
629 iFrame->SetType(AVC::EImplemented); |
|
630 } |
|
631 break; |
|
632 case KErrAvrcpMetadataInvalidCommand: |
|
633 case KErrAvrcpMetadataInvalidParameter: |
|
634 case KErrAvrcpMetadataParameterNotFound: |
|
635 case KErrAvrcpMetadataInternalError: |
|
636 case KErrAvrcpAirInvalidCommand: |
|
637 case KErrAvrcpAirInvalidParameter: |
|
638 case KErrAvrcpAirParameterNotFound: |
|
639 case KErrAvrcpAirInternalError: |
|
640 case KErrAvrcpAirSuccess: |
|
641 case KErrAvrcpAirUidChanged: |
|
642 case KErrAvrcpAirReserved: |
|
643 case KErrAvrcpAirInvalidDirection: |
|
644 case KErrAvrcpAirNotADirectory: |
|
645 case KErrAvrcpAirDoesNotExist: |
|
646 case KErrAvrcpAirInvalidScope: |
|
647 case KErrAvrcpAirRangeOutOfBounds: |
|
648 case KErrAvrcpAirUidIsADirectory: |
|
649 case KErrAvrcpAirMediaInUse: |
|
650 case KErrAvrcpAirNowPlayingListFull: |
|
651 case KErrAvrcpAirSearchNotSupported: |
|
652 case KErrAvrcpAirSearchInProgress: |
|
653 case KErrAvrcpAirInvalidPlayerId: |
|
654 case KErrAvrcpAirPlayerNotBrowesable: |
|
655 case KErrAvrcpAirPlayerNotAddressed: |
|
656 case KErrAvrcpAirNoValidSearchResults: |
|
657 case KErrAvrcpAirNoAvailablePlayers: |
|
658 case KErrAvrcpAirAddressedPlayerChanged: |
|
659 { |
|
660 // If this fails, we're OOM (it only contains a NewL) |
|
661 // so we can't send the error response - just give up |
|
662 TRAPD(err, GenerateMetadataRejectPayloadL(aErr)); |
|
663 err = err; // avoid warning about not using this |
|
664 break; |
|
665 } |
|
666 default: |
|
667 iFrame->SetType(AVC::ENotImplemented); |
|
668 } |
|
669 iFrame->SetFrameType(AVC::EResponse); |
|
670 } |
|
671 |
|
672 /** Gets this command's AV/C frame. |
|
673 @return the AV/C frame for this command |
|
674 */ |
|
675 const CAVCFrame& CControlCommand::Frame() const |
|
676 { |
|
677 LOG_FUNC |
|
678 return *iFrame; |
|
679 } |
|
680 |
|
681 const TDesC8& CControlCommand::Data() const |
|
682 { |
|
683 LOG_FUNC |
|
684 return iFrame->Data(); |
|
685 } |
|
686 |
|
687 SymbianAvctp::TMessageType CControlCommand::MessageType() const |
|
688 { |
|
689 LOG_FUNC |
|
690 return (iFrame->FrameType() == AVC::ECommand) ? SymbianAvctp::ECommand : SymbianAvctp::EResponse; |
|
691 } |
|
692 |
|
693 /** Gets the button action from this command's AV/C frame. |
|
694 This is only valid on passthrough commands. |
|
695 |
|
696 @return The button action. |
|
697 */ |
|
698 AVCPanel::TButtonAction CControlCommand::ButtonAct() const |
|
699 { |
|
700 LOG_FUNC |
|
701 AVCPanel::TButtonAction act; |
|
702 iFrame->ButtonAct(act); |
|
703 return act; |
|
704 } |
|
705 |
|
706 /** Gets whether this command is currently assumed to be a click. |
|
707 |
|
708 This is used to support the click facility offered by RemCon, which |
|
709 is not offered by AVRCP. As such AVRCP internally simulates outgoing |
|
710 clicks by generating a press and release for one RemCon click. When |
|
711 responses are received we know that if a command is a click we should |
|
712 send only one response up to RemCon. |
|
713 |
|
714 Incoming passthrough press commands are assumed to be click until |
|
715 the hold timer expires. When a matching release is received we can |
|
716 then tell whether we need to send a single click up to RemCon, or |
|
717 a release to match the press that was sent when the hold timer expired. |
|
718 |
|
719 @return ETrue is this is a click. EFalse if not. |
|
720 */ |
|
721 TBool CControlCommand::Click() const |
|
722 { |
|
723 LOG_FUNC |
|
724 return iIsClick; |
|
725 } |
|
726 |
|
727 /** Sets whether this command is currently assumed to be a click |
|
728 or not. |
|
729 |
|
730 @see CRcpcommand::Click() |
|
731 @param aIsClick ETrue to set this as click. EFalse to set this as |
|
732 not click. |
|
733 */ |
|
734 void CControlCommand::SetClick(TBool aIsClick) |
|
735 { |
|
736 LOG_FUNC |
|
737 iIsClick = aIsClick; |
|
738 } |
|
739 |
|
740 /** Sets the RemCon data to indicate what button action this |
|
741 command is. This function is only valid for commands in the |
|
742 core api. |
|
743 |
|
744 @param aButtonAct The RemCon button action for this command. |
|
745 @param aCommand Whether this is a command. This is needed |
|
746 because the command data is at a different offset for |
|
747 commands and responses. |
|
748 */ |
|
749 void CControlCommand::SetCoreButtonAction(TRemConCoreApiButtonAction aButtonAct, TBool aCommand) |
|
750 { |
|
751 LOG_FUNC |
|
752 |
|
753 TInt offset = aCommand ? KRemConCoreApiButtonDataOffset + KRemConCoreApiCommandDataOffset |
|
754 : KRemConCoreApiButtonDataOffset + KRemConCoreApiResponseDataOffset; |
|
755 |
|
756 AvrcpUtils::SetCommandDataFromInt(iCommandData, offset, |
|
757 KRemConCoreApiButtonDataLength, aButtonAct); |
|
758 } |
|
759 /** ReSets the RemCon data to indicate what button action this |
|
760 command is. This function is called when we the command is being re-used to generate a |
|
761 new command to remconServ. |
|
762 |
|
763 @param aButtonAct The RemCon button action for this command. |
|
764 @param aCommand Whether this is a command. This is needed |
|
765 because the command data is at a different offset for |
|
766 commands and responses. |
|
767 */ |
|
768 void CControlCommand::ReSetCoreButtonActionL(TRemConCoreApiButtonAction aButtonAct, TBool aCommand) |
|
769 { |
|
770 LOG_FUNC |
|
771 |
|
772 if (iCommandData.MaxLength() < KRemConCoreApiButtonDataLength) |
|
773 { |
|
774 iCommandData.Close(); |
|
775 iCommandData.CreateMaxL(KRemConCoreApiButtonDataLength); |
|
776 } |
|
777 |
|
778 SetCoreButtonAction(aButtonAct, aCommand); |
|
779 } |
|
780 |
|
781 /** Inserts the results at the beginning of this command's data. |
|
782 If the data buffer is not large enough it will be ReAlloced to |
|
783 allow the insertion. |
|
784 |
|
785 @return The result to pass to RemCon. KErrNone for an AV/C accepted. |
|
786 KErrNotSupported for an AV/C not implemented. KErrGeneral |
|
787 for an AV/C rejected. |
|
788 */ |
|
789 TInt CControlCommand::InsertCoreResult(TInt aResult) |
|
790 { |
|
791 LOG_FUNC |
|
792 TInt err = KErrNone; |
|
793 TInt requiredLength = KRemConCoreApiResultDataLength + iCommandData.Length(); |
|
794 |
|
795 if(iCommandData.Length() >= requiredLength) |
|
796 { |
|
797 // Insert data to write result into |
|
798 iCommandData.Insert(0, KRemConCoreApiResultPad); |
|
799 } |
|
800 else |
|
801 { |
|
802 // need longer buffer |
|
803 err = iCommandData.ReAlloc(requiredLength); |
|
804 if(!err) |
|
805 { |
|
806 iCommandData.Insert(0, KRemConCoreApiResultPad); |
|
807 } |
|
808 else |
|
809 { |
|
810 return err; |
|
811 } |
|
812 } |
|
813 |
|
814 AvrcpUtils::SetCommandDataFromInt(iCommandData, 0, |
|
815 KRemConCoreApiResultDataLength, aResult); |
|
816 return err; |
|
817 } |
|
818 |
|
819 /** |
|
820 Sets the result of set absolute volume response into this command's data |
|
821 */ |
|
822 TInt CControlCommand::SetSetAbsoluteVolumeResult(const CAVCFrame& aFrame) |
|
823 { |
|
824 TInt err = KErrNone; |
|
825 TRAP(err, DoSetAbsoluteVolumeResultL(aFrame)); |
|
826 if (err != KErrNone) |
|
827 { |
|
828 // Ensure the client can receive an error in case of |
|
829 // DoSetAbsoluteVolumeResultL leaves out. |
|
830 iCommandData.Zero(); |
|
831 TPckgBuf<TInt> errBuf(err); |
|
832 iCommandData.Append(errBuf); |
|
833 iCommandData.SetLength(iCommandData.MaxLength()); |
|
834 } |
|
835 return err; |
|
836 } |
|
837 |
|
838 void CControlCommand::DoSetAbsoluteVolumeResultL(const CAVCFrame& aFrame) |
|
839 { |
|
840 RRemConAbsoluteVolumeResponse absVol; |
|
841 absVol.iError = KErrGeneral; |
|
842 absVol.iMaxVolume = KAvrcpMaxAbsoluteVolume; |
|
843 |
|
844 CleanupClosePushL(absVol); |
|
845 |
|
846 switch(aFrame.Type()) |
|
847 { |
|
848 case AVC::EAccepted: |
|
849 { |
|
850 if (aFrame.Data().Length() == KLengthSetAbsoluteVolumeResponse) |
|
851 { |
|
852 absVol.iError = KErrNone; |
|
853 TUint volumeOffset = KLengthSetAbsoluteVolumeResponse - 1; |
|
854 absVol.iVolume = KAbsoluteVolumeMask & aFrame.Data()[volumeOffset]; |
|
855 } |
|
856 break; |
|
857 } |
|
858 case AVC::ERejected: // fall through |
|
859 case AVC::ENotImplemented: |
|
860 break; |
|
861 default: |
|
862 break; |
|
863 } |
|
864 |
|
865 absVol.WriteL(iCommandData); |
|
866 CleanupStack::PopAndDestroy(&absVol); |
|
867 } |
|
868 /** |
|
869 Sets the result of volume changed notification response into this command's |
|
870 data. |
|
871 */ |
|
872 TInt CControlCommand::SetNotifyVolumeChangeResult(const CAVCFrame& aFrame) |
|
873 { |
|
874 TInt err = KErrNone; |
|
875 TRAP(err, DoSetNotifyVolumeChangeResultL(aFrame)); |
|
876 if (err == KErrNone) |
|
877 { |
|
878 // Through AVC::TCType the RemCon sever can know whether the response |
|
879 // is an Interim or Changed or any other responses, so the RemCon |
|
880 // server can decide to remove the notify command from its |
|
881 // outgoingsent queue or not. |
|
882 iFrame->SetType(aFrame.Type()); |
|
883 } |
|
884 else |
|
885 { |
|
886 // Ensure the client can receive an error in case of |
|
887 // DoSetNotifyVolumeChangeResultL leaves out. |
|
888 iCommandData.Zero(); |
|
889 TPckgBuf<TInt> errBuf(KErrGeneral); |
|
890 iCommandData.Append(errBuf); |
|
891 iCommandData.SetLength(iCommandData.MaxLength()); |
|
892 |
|
893 // Setting AVC::TCType to ERejected is intended to let the RemCon |
|
894 // server to remove the notify command from its outgoingsent queue |
|
895 // in case of DoSetNotifyVolumeChangeResultL leaves out. |
|
896 iFrame->SetType(AVC::ERejected); |
|
897 } |
|
898 |
|
899 return err; |
|
900 } |
|
901 |
|
902 void CControlCommand::DoSetNotifyVolumeChangeResultL(const CAVCFrame& aFrame) |
|
903 { |
|
904 if (iCommandData.MaxLength() < KAbsoluteVolumeResponseDataSize) |
|
905 { |
|
906 iCommandData.Close(); |
|
907 iCommandData.CreateL(KAbsoluteVolumeResponseDataSize); |
|
908 } |
|
909 |
|
910 RRemConAbsoluteVolumeResponse absVol; |
|
911 absVol.iError = KErrGeneral; |
|
912 absVol.iMaxVolume = KAvrcpMaxAbsoluteVolume; |
|
913 |
|
914 CleanupClosePushL(absVol); |
|
915 |
|
916 switch(aFrame.Type()) |
|
917 { |
|
918 case AVC::EInterim: |
|
919 case AVC::EChanged: |
|
920 { |
|
921 if (aFrame.Data().Length() == KLengthNotifyVolumeChangeResponse) |
|
922 { |
|
923 absVol.iError = KErrNone; |
|
924 TUint volumeOffset = KLengthNotifyVolumeChangeResponse - 1; |
|
925 absVol.iVolume = KAbsoluteVolumeMask & aFrame.Data()[volumeOffset]; |
|
926 } |
|
927 break; |
|
928 } |
|
929 case AVC::ERejected: // fall through |
|
930 case AVC::ENotImplemented: |
|
931 break; |
|
932 default: |
|
933 break; |
|
934 } |
|
935 absVol.WriteL(iCommandData); |
|
936 CleanupStack::PopAndDestroy(&absVol); |
|
937 } |
|
938 //------------------------------------------------------------------------------------ |
|
939 // Internal utility functions |
|
940 //------------------------------------------------------------------------------------ |
|
941 |
|
942 /** Fills in command info from an AVC Control. |
|
943 |
|
944 This functions sets iInterfaceUid, iOperationId and iCommandData |
|
945 to the correct values according to iFrame. The format of iCommandData |
|
946 is defined by RemCon and is dependent on iInterfaceUid and iOperationId. |
|
947 |
|
948 @return KErrNone If the frame has been parsed successfully. |
|
949 @return KErrNotSupported This frame represents a command for which a |
|
950 RemCon converter or client side interface |
|
951 cannot be found. |
|
952 @return System wide error code. |
|
953 */ |
|
954 TInt CControlCommand::ParseIncomingKnownOpcodeL(MRemConBearerObserver& aObserver) |
|
955 { |
|
956 LOG_FUNC |
|
957 TInt err = KErrNotSupported; |
|
958 |
|
959 AVC::TCType cType = iFrame->Type(); |
|
960 |
|
961 switch(iFrame->Opcode()) |
|
962 { |
|
963 case AVC::EPassThrough: |
|
964 { |
|
965 if(iFrame->Data().Length() < KAVCPassthroughFrameLength) |
|
966 { |
|
967 LEAVEL(KErrCorrupt); |
|
968 } |
|
969 if (iFrame->SubunitType() != AVC::EPanel) |
|
970 { |
|
971 LEAVEL(KErrNotSupported); |
|
972 } |
|
973 |
|
974 TUint8 avrcpOp; |
|
975 if (cType != AVC::EGeneralEnquiry && cType == AVC::EControl) |
|
976 { |
|
977 iCommandData.CreateMaxL(KRemConCoreApiButtonDataLength); |
|
978 err = iFrame->OperationId(avrcpOp); |
|
979 if (err == KErrNone) |
|
980 { |
|
981 if (avrcpOp!=AVCPanel::EVendorUnique) |
|
982 { |
|
983 err = AvrcpToRemConOperation(avrcpOp, iOperationId, iInterfaceUid); |
|
984 } |
|
985 else |
|
986 { |
|
987 err = ParseVendorUniquePassthroughCommand(aObserver); |
|
988 } |
|
989 } |
|
990 |
|
991 if (err!=KErrNone) |
|
992 { |
|
993 err = KErrAvrcpInvalidOperationId; |
|
994 } |
|
995 } |
|
996 else |
|
997 { |
|
998 iCommandData.Close(); |
|
999 iCommandData.CreateL(KAVCFrameMaxLength); |
|
1000 TRemConMessageType message = ERemConCommand; |
|
1001 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1002 iFrame->Data(), |
|
1003 iFrame->Data(), |
|
1004 iInterfaceUid, |
|
1005 iOperationId, |
|
1006 message, |
|
1007 iCommandData); |
|
1008 } |
|
1009 break; |
|
1010 } |
|
1011 case AVC::EUnitInfo: |
|
1012 { |
|
1013 if (iFrame->Type() == AVC::EStatus) |
|
1014 { |
|
1015 CAVCFrame* resp = AvrcpCommandFramer::UnitInfoResponseL(); |
|
1016 delete iFrame; |
|
1017 iFrame = resp; |
|
1018 err = KErrCompletion; // since bearer has done its job without client needed |
|
1019 } |
|
1020 else |
|
1021 { |
|
1022 err = KErrAvrcpInvalidCType; |
|
1023 } |
|
1024 break; |
|
1025 } |
|
1026 case AVC::ESubunitInfo: |
|
1027 { |
|
1028 if (iFrame->Type() == AVC::EStatus) |
|
1029 { |
|
1030 CAVCFrame* resp = AvrcpCommandFramer::SubunitInfoResponseL(); |
|
1031 delete iFrame; |
|
1032 iFrame = resp; |
|
1033 err = KErrCompletion; // since bearer has done its job without client needed |
|
1034 } |
|
1035 else |
|
1036 { |
|
1037 err = KErrAvrcpInvalidCType; |
|
1038 } |
|
1039 break; |
|
1040 } |
|
1041 |
|
1042 default: |
|
1043 { |
|
1044 iCommandData.Close(); |
|
1045 iCommandData.CreateL(KAVCFrameMaxLength); |
|
1046 TRemConMessageType message = ERemConCommand; |
|
1047 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1048 iFrame->Data(), |
|
1049 iFrame->Data(), |
|
1050 iInterfaceUid, |
|
1051 iOperationId, |
|
1052 message, |
|
1053 iCommandData); |
|
1054 break; |
|
1055 } |
|
1056 } |
|
1057 |
|
1058 return err; |
|
1059 } |
|
1060 |
|
1061 |
|
1062 /** Fills in command info from an AVC Vendor Dependent message. |
|
1063 |
|
1064 This functions sets iInterfaceUid, iOperationId and iCommandData |
|
1065 to the correct values according to iFrame. The format of iCommandData |
|
1066 is defined by RemCon and is dependent on iInterfaceUid and iOperationId. |
|
1067 The AVC frame's length is checked that it at least contains the vendor id. |
|
1068 |
|
1069 @param aObserver An observer to be used to obtain a converter. |
|
1070 @return KErrNone If the frame has been parsed successfully. |
|
1071 @return KErrNotSupported This frame represents a command for which a |
|
1072 RemCon converter or client side interface |
|
1073 cannot be found. |
|
1074 @return KErrAvrcpInvalidCType The CType specified in this frame is invalid. |
|
1075 @return KErrAvrcpMetadataInvalidCommand The AVRCP command is invalid. |
|
1076 @return KErrAvrcpMetadataInvalidParameter The AVRCP parameter is invalid. |
|
1077 @return KErrAvrcpMetadataParameterNotFound The AVRCP parameter was not found. |
|
1078 @return KErrAvrcpMetadataInternalError An AVRCP internal error occurred (such as out-of-memory, |
|
1079 or an inter-process communication error) |
|
1080 @return System wide error code. |
|
1081 */ |
|
1082 TInt CControlCommand::ParseIncomingVendorCommandL(MRemConBearerObserver& aObserver, CAVRCPFragmenter& aFragmenter) |
|
1083 { |
|
1084 LOG_FUNC |
|
1085 TInt err = KErrNone; |
|
1086 |
|
1087 SetVendorInfoL(EFalse); // set id and payload; leaves if not enough space available |
|
1088 |
|
1089 if (iVendorId!=KBluetoothSIGVendorId) |
|
1090 { |
|
1091 iCommandData.Close(); |
|
1092 iCommandData.CreateL(KAVCFrameMaxLength); |
|
1093 |
|
1094 TRemConMessageType message = ERemConCommand; |
|
1095 |
|
1096 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1097 iFrame->Data(), |
|
1098 iFrame->Data(), |
|
1099 iInterfaceUid, |
|
1100 iOperationId, |
|
1101 message, |
|
1102 iCommandData); |
|
1103 } |
|
1104 else |
|
1105 { |
|
1106 // process v>1.0 version of AVRCP |
|
1107 // which use vendor dependent frames to extend v1.0 of AVRCP |
|
1108 // the vendor code has the value for the BT SIG |
|
1109 if (iFrame->SubunitType() != AVC::EPanel) |
|
1110 { |
|
1111 // this is for Control not Metadata |
|
1112 return KErrNotSupported; |
|
1113 } |
|
1114 |
|
1115 err = ParseMetadataTransferVendorCommand(aFragmenter); |
|
1116 if (err == KErrNone) |
|
1117 { |
|
1118 // Check that the interface UID is non-zero |
|
1119 __ASSERT_DEBUG(iInterfaceUid != TUid::Uid(0), AvrcpUtils::Panic(EAvrcpInterfaceUidNotSet)); |
|
1120 } |
|
1121 } |
|
1122 return err; |
|
1123 } |
|
1124 |
|
1125 |
|
1126 /** Creates RemCon command information from iFrame. |
|
1127 |
|
1128 This functions sets iInterfaceUid, iOperationId and iCommandData |
|
1129 to the correct values according to iFrame. The format of iCommandData |
|
1130 is defined by the interface, iInterfaceUid and is dependent on |
|
1131 iOperationId. A converter should be able to be found as this response |
|
1132 is a result of an outgoing command on this interface. |
|
1133 |
|
1134 @param aObserver An observer used to get a converter. |
|
1135 @param aFrame The AV/C frame for this command. |
|
1136 */ |
|
1137 void CControlCommand::ParseIncomingUnknownResponse(MRemConBearerObserver& aObserver, |
|
1138 const CAVCFrame& aFrame) |
|
1139 { |
|
1140 LOG_FUNC |
|
1141 // We need to pass a response up to RemCon even if we can't get a |
|
1142 // converter to generate a decent response so we don't |
|
1143 |
|
1144 iCommandData.Close(); |
|
1145 TInt err = iCommandData.Create(KAVCFrameMaxLength); |
|
1146 if(!err) |
|
1147 { |
|
1148 TRemConMessageType type = ERemConResponse; // output param |
|
1149 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1150 aFrame.Data(), aFrame.Data(), iInterfaceUid, iOperationId, type, iCommandData); |
|
1151 } |
|
1152 } |
|
1153 |
|
1154 /** Translates from an AVC operation id to RemCon's core interface. |
|
1155 |
|
1156 @param aAvrcpOp The AVC passthrough operation id. |
|
1157 @param aRemConOp On return the RemCon operation id within the core interface. |
|
1158 @return KErrNone If the operation has been translated successfully. |
|
1159 @return KErrNotSupported If the operation does not correspond to one |
|
1160 in the RemCon core interface. |
|
1161 */ |
|
1162 TInt CControlCommand::AvrcpToRemConOperation(TUint aAvrcpOp, TUint& aRemConOp, TUid& aRemConIf) |
|
1163 { |
|
1164 LOG_STATIC_FUNC |
|
1165 TInt err = KErrNone; |
|
1166 |
|
1167 //TBH setting here as most are for the Core API |
|
1168 //some cases will override |
|
1169 aRemConIf = TUid::Uid(KRemConCoreApiUid); |
|
1170 |
|
1171 switch(aAvrcpOp) |
|
1172 { |
|
1173 case AVCPanel::ESelect: |
|
1174 aRemConOp = ERemConCoreApiSelect; |
|
1175 break; |
|
1176 case AVCPanel::EUp: |
|
1177 aRemConOp = ERemConCoreApiUp; |
|
1178 break; |
|
1179 case AVCPanel::EDown: |
|
1180 aRemConOp = ERemConCoreApiDown; |
|
1181 break; |
|
1182 case AVCPanel::ELeft: |
|
1183 aRemConOp = ERemConCoreApiLeft; |
|
1184 break; |
|
1185 case AVCPanel::ERight: |
|
1186 aRemConOp = ERemConCoreApiRight; |
|
1187 break; |
|
1188 case AVCPanel::ERightUp: |
|
1189 aRemConOp = ERemConCoreApiRightUp; |
|
1190 break; |
|
1191 case AVCPanel::ERightDown: |
|
1192 aRemConOp = ERemConCoreApiRightDown; |
|
1193 break; |
|
1194 case AVCPanel::ELeftUp: |
|
1195 aRemConOp = ERemConCoreApiLeftUp; |
|
1196 break; |
|
1197 case AVCPanel::ELeftDown: |
|
1198 aRemConOp = ERemConCoreApiLeftDown; |
|
1199 break; |
|
1200 case AVCPanel::ERootMenu: |
|
1201 aRemConOp = ERemConCoreApiRootMenu; |
|
1202 break; |
|
1203 case AVCPanel::ESetupMenu: |
|
1204 aRemConOp = ERemConCoreApiSetupMenu; |
|
1205 break; |
|
1206 case AVCPanel::EContentsMenu: |
|
1207 aRemConOp = ERemConCoreApiContentsMenu; |
|
1208 break; |
|
1209 case AVCPanel::EFavoriteMenu: |
|
1210 aRemConOp = ERemConCoreApiFavoriteMenu; |
|
1211 break; |
|
1212 case AVCPanel::EExit: |
|
1213 aRemConOp = ERemConCoreApiExit; |
|
1214 break; |
|
1215 case AVCPanel::E0: |
|
1216 aRemConOp = ERemConCoreApi0; |
|
1217 break; |
|
1218 case AVCPanel::E1: |
|
1219 aRemConOp = ERemConCoreApi1; |
|
1220 break; |
|
1221 case AVCPanel::E2: |
|
1222 aRemConOp = ERemConCoreApi2; |
|
1223 break; |
|
1224 case AVCPanel::E3: |
|
1225 aRemConOp = ERemConCoreApi3; |
|
1226 break; |
|
1227 case AVCPanel::E4: |
|
1228 aRemConOp = ERemConCoreApi4; |
|
1229 break; |
|
1230 case AVCPanel::E5: |
|
1231 aRemConOp = ERemConCoreApi5; |
|
1232 break; |
|
1233 case AVCPanel::E6: |
|
1234 aRemConOp = ERemConCoreApi6; |
|
1235 break; |
|
1236 case AVCPanel::E7: |
|
1237 aRemConOp = ERemConCoreApi7; |
|
1238 break; |
|
1239 case AVCPanel::E8: |
|
1240 aRemConOp = ERemConCoreApi8; |
|
1241 break; |
|
1242 case AVCPanel::E9: |
|
1243 aRemConOp = ERemConCoreApi9; |
|
1244 break; |
|
1245 case AVCPanel::EDot: |
|
1246 aRemConOp = ERemConCoreApiDot; |
|
1247 break; |
|
1248 case AVCPanel::EEnter: |
|
1249 aRemConOp = ERemConCoreApiEnter; |
|
1250 break; |
|
1251 case AVCPanel::EClear: |
|
1252 aRemConOp = ERemConCoreApiClear; |
|
1253 break; |
|
1254 case AVCPanel::EChannelUp: |
|
1255 aRemConOp = ERemConCoreApiChannelUp; |
|
1256 break; |
|
1257 case AVCPanel::EChannelDown: |
|
1258 aRemConOp = ERemConCoreApiChannelDown; |
|
1259 break; |
|
1260 case AVCPanel::EPreviousChannel: |
|
1261 aRemConOp = ERemConCoreApiPreviousChannel; |
|
1262 break; |
|
1263 case AVCPanel::ESoundSelect: |
|
1264 aRemConOp = ERemConCoreApiSoundSelect; |
|
1265 break; |
|
1266 case AVCPanel::EInputSelect: |
|
1267 aRemConOp = ERemConCoreApiInputSelect; |
|
1268 break; |
|
1269 case AVCPanel::EDisplayInformation: |
|
1270 aRemConOp = ERemConCoreApiDisplayInformation; |
|
1271 break; |
|
1272 case AVCPanel::EHelp: |
|
1273 aRemConOp = ERemConCoreApiHelp; |
|
1274 break; |
|
1275 case AVCPanel::EPageUp: |
|
1276 aRemConOp = ERemConCoreApiPageUp; |
|
1277 break; |
|
1278 case AVCPanel::EPageDown: |
|
1279 aRemConOp = ERemConCoreApiPageDown; |
|
1280 break; |
|
1281 case AVCPanel::EPower: |
|
1282 aRemConOp = ERemConCoreApiPower; |
|
1283 break; |
|
1284 case AVCPanel::EVolumeUp: |
|
1285 aRemConOp = ERemConCoreApiVolumeUp; |
|
1286 break; |
|
1287 case AVCPanel::EVolumeDown: |
|
1288 aRemConOp = ERemConCoreApiVolumeDown; |
|
1289 break; |
|
1290 case AVCPanel::EMute: |
|
1291 aRemConOp = ERemConCoreApiMute; |
|
1292 break; |
|
1293 case AVCPanel::EPlay: |
|
1294 aRemConOp = ERemConCoreApiPlay; |
|
1295 break; |
|
1296 case AVCPanel::EStop: |
|
1297 aRemConOp = ERemConCoreApiStop; |
|
1298 break; |
|
1299 case AVCPanel::EPause: |
|
1300 aRemConOp = ERemConCoreApiPause; |
|
1301 break; |
|
1302 case AVCPanel::ERecord: |
|
1303 aRemConOp = ERemConCoreApiRecord; |
|
1304 break; |
|
1305 case AVCPanel::ERewind: |
|
1306 aRemConOp = ERemConCoreApiRewind; |
|
1307 break; |
|
1308 case AVCPanel::EFastForward: |
|
1309 aRemConOp = ERemConCoreApiFastForward; |
|
1310 break; |
|
1311 case AVCPanel::EEject: |
|
1312 aRemConOp = ERemConCoreApiEject; |
|
1313 break; |
|
1314 case AVCPanel::EForward: |
|
1315 aRemConOp = ERemConCoreApiForward; |
|
1316 break; |
|
1317 case AVCPanel::EBackward: |
|
1318 aRemConOp = ERemConCoreApiBackward; |
|
1319 break; |
|
1320 case AVCPanel::EAngle: |
|
1321 aRemConOp = ERemConCoreApiAngle; |
|
1322 break; |
|
1323 case AVCPanel::ESubpicture: |
|
1324 aRemConOp = ERemConCoreApiSubpicture; |
|
1325 break; |
|
1326 case AVCPanel::EF1: |
|
1327 aRemConOp = ERemConCoreApiF1; |
|
1328 break; |
|
1329 case AVCPanel::EF2: |
|
1330 aRemConOp = ERemConCoreApiF2; |
|
1331 break; |
|
1332 case AVCPanel::EF3: |
|
1333 aRemConOp = ERemConCoreApiF3; |
|
1334 break; |
|
1335 case AVCPanel::EF4: |
|
1336 aRemConOp = ERemConCoreApiF4; |
|
1337 break; |
|
1338 case AVCPanel::EF5: |
|
1339 aRemConOp = ERemConCoreApiF5; |
|
1340 break; |
|
1341 case AVCPanel::EVendorUnique: |
|
1342 default: |
|
1343 err = KErrNotSupported; |
|
1344 } |
|
1345 |
|
1346 return err; |
|
1347 } |
|
1348 |
|
1349 |
|
1350 TInt CControlCommand::ParseVendorUniquePassthroughCommand(MRemConBearerObserver& aObserver) |
|
1351 { |
|
1352 TInt err = KErrNone; |
|
1353 TRAP(err, SetVendorInfoL(ETrue)); // set id and payload; leaves if not enough space available |
|
1354 |
|
1355 if (err == KErrNone && iVendorId == KBluetoothSIGVendorId) |
|
1356 { |
|
1357 // it's one of the v1.3 (or later!) MT commands |
|
1358 err = ParseMetadataTransferPassthroughCommand(); |
|
1359 } |
|
1360 else |
|
1361 { |
|
1362 iCommandData.Close(); |
|
1363 TRAP(err, iCommandData.CreateL(KAVCFrameMaxLength)); |
|
1364 if(err == KErrNone) |
|
1365 { |
|
1366 TRemConMessageType message = ERemConCommand; |
|
1367 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1368 iFrame->Data(), |
|
1369 iFrame->Data(), |
|
1370 iInterfaceUid, |
|
1371 iOperationId, |
|
1372 message, |
|
1373 iCommandData); |
|
1374 } |
|
1375 } |
|
1376 |
|
1377 return err; |
|
1378 } |
|
1379 |
|
1380 /** Translates from RemCon's core interface to an AVC operation id. |
|
1381 |
|
1382 @param aRemConOp The RemCon operation id within the core interface. |
|
1383 @param aAvrcpOp On return the AVC passthrough operation id. |
|
1384 @return KErrNone If the operation has been translated successfully. |
|
1385 @return KErrNotSupported If the operation does not correspond to one |
|
1386 provided by AVRCP. |
|
1387 */ |
|
1388 TInt CControlCommand::RemConToAvrcpOperation(TUint aRemConOp, AVCPanel::TOperationId& aAvrcpOp) |
|
1389 { |
|
1390 LOG_STATIC_FUNC |
|
1391 TInt err = KErrNone; |
|
1392 switch(aRemConOp) |
|
1393 { |
|
1394 case ERemConCoreApiSelect: |
|
1395 aAvrcpOp = AVCPanel::ESelect; |
|
1396 break; |
|
1397 case ERemConCoreApiUp: |
|
1398 aAvrcpOp = AVCPanel::EUp; |
|
1399 break; |
|
1400 case ERemConCoreApiDown: |
|
1401 aAvrcpOp = AVCPanel::EDown; |
|
1402 break; |
|
1403 case ERemConCoreApiLeft: |
|
1404 aAvrcpOp = AVCPanel::ELeft; |
|
1405 break; |
|
1406 case ERemConCoreApiRight: |
|
1407 aAvrcpOp = AVCPanel::ERight; |
|
1408 break; |
|
1409 case ERemConCoreApiRightUp: |
|
1410 aAvrcpOp = AVCPanel::ERightUp; |
|
1411 break; |
|
1412 case ERemConCoreApiRightDown: |
|
1413 aAvrcpOp = AVCPanel::ERightDown; |
|
1414 break; |
|
1415 case ERemConCoreApiLeftUp: |
|
1416 aAvrcpOp = AVCPanel::ELeftUp; |
|
1417 break; |
|
1418 case ERemConCoreApiLeftDown: |
|
1419 aAvrcpOp = AVCPanel::ELeftDown; |
|
1420 break; |
|
1421 case ERemConCoreApiRootMenu: |
|
1422 aAvrcpOp = AVCPanel::ERootMenu; |
|
1423 break; |
|
1424 case ERemConCoreApiSetupMenu: |
|
1425 aAvrcpOp = AVCPanel::ESetupMenu; |
|
1426 break; |
|
1427 case ERemConCoreApiContentsMenu: |
|
1428 aAvrcpOp = AVCPanel::EContentsMenu; |
|
1429 break; |
|
1430 case ERemConCoreApiFavoriteMenu: |
|
1431 aAvrcpOp = AVCPanel::EFavoriteMenu; |
|
1432 break; |
|
1433 case ERemConCoreApiExit: |
|
1434 aAvrcpOp = AVCPanel::EExit; |
|
1435 break; |
|
1436 case ERemConCoreApi0: |
|
1437 aAvrcpOp = AVCPanel::E0; |
|
1438 break; |
|
1439 case ERemConCoreApi1: |
|
1440 aAvrcpOp = AVCPanel::E1; |
|
1441 break; |
|
1442 case ERemConCoreApi2: |
|
1443 aAvrcpOp = AVCPanel::E2; |
|
1444 break; |
|
1445 case ERemConCoreApi3: |
|
1446 aAvrcpOp = AVCPanel::E3; |
|
1447 break; |
|
1448 case ERemConCoreApi4: |
|
1449 aAvrcpOp = AVCPanel::E4; |
|
1450 break; |
|
1451 case ERemConCoreApi5: |
|
1452 aAvrcpOp = AVCPanel::E5; |
|
1453 break; |
|
1454 case ERemConCoreApi6: |
|
1455 aAvrcpOp = AVCPanel::E6; |
|
1456 break; |
|
1457 case ERemConCoreApi7: |
|
1458 aAvrcpOp = AVCPanel::E7; |
|
1459 break; |
|
1460 case ERemConCoreApi8: |
|
1461 aAvrcpOp = AVCPanel::E8; |
|
1462 break; |
|
1463 case ERemConCoreApi9: |
|
1464 aAvrcpOp = AVCPanel::E9; |
|
1465 break; |
|
1466 case ERemConCoreApiDot: |
|
1467 aAvrcpOp = AVCPanel::EDot; |
|
1468 break; |
|
1469 case ERemConCoreApiEnter: |
|
1470 aAvrcpOp = AVCPanel::EEnter; |
|
1471 break; |
|
1472 case ERemConCoreApiClear: |
|
1473 aAvrcpOp = AVCPanel::EClear; |
|
1474 break; |
|
1475 case ERemConCoreApiChannelUp: |
|
1476 aAvrcpOp = AVCPanel::EChannelUp; |
|
1477 break; |
|
1478 case ERemConCoreApiChannelDown: |
|
1479 aAvrcpOp = AVCPanel::EChannelDown; |
|
1480 break; |
|
1481 case ERemConCoreApiPreviousChannel: |
|
1482 aAvrcpOp = AVCPanel::EPreviousChannel; |
|
1483 break; |
|
1484 case ERemConCoreApiSoundSelect: |
|
1485 aAvrcpOp = AVCPanel::ESoundSelect; |
|
1486 break; |
|
1487 case ERemConCoreApiInputSelect: |
|
1488 aAvrcpOp = AVCPanel::EInputSelect; |
|
1489 break; |
|
1490 case ERemConCoreApiDisplayInformation: |
|
1491 aAvrcpOp = AVCPanel::EDisplayInformation; |
|
1492 break; |
|
1493 case ERemConCoreApiHelp: |
|
1494 aAvrcpOp = AVCPanel::EHelp; |
|
1495 break; |
|
1496 case ERemConCoreApiPageUp: |
|
1497 aAvrcpOp = AVCPanel::EPageUp; |
|
1498 break; |
|
1499 case ERemConCoreApiPageDown: |
|
1500 aAvrcpOp = AVCPanel::EPageDown; |
|
1501 break; |
|
1502 case ERemConCoreApiPower: |
|
1503 aAvrcpOp = AVCPanel::EPower; |
|
1504 break; |
|
1505 case ERemConCoreApiVolumeUp: |
|
1506 aAvrcpOp = AVCPanel::EVolumeUp; |
|
1507 break; |
|
1508 case ERemConCoreApiVolumeDown: |
|
1509 aAvrcpOp = AVCPanel::EVolumeDown; |
|
1510 break; |
|
1511 case ERemConCoreApiMute: |
|
1512 aAvrcpOp = AVCPanel::EMute; |
|
1513 break; |
|
1514 case ERemConCoreApiPlay: |
|
1515 aAvrcpOp = AVCPanel::EPlay; |
|
1516 break; |
|
1517 case ERemConCoreApiStop: |
|
1518 aAvrcpOp = AVCPanel::EStop; |
|
1519 break; |
|
1520 case ERemConCoreApiPause: |
|
1521 aAvrcpOp = AVCPanel::EPause; |
|
1522 break; |
|
1523 case ERemConCoreApiRecord: |
|
1524 aAvrcpOp = AVCPanel::ERecord; |
|
1525 break; |
|
1526 case ERemConCoreApiRewind: |
|
1527 aAvrcpOp = AVCPanel::ERewind; |
|
1528 break; |
|
1529 case ERemConCoreApiFastForward: |
|
1530 aAvrcpOp = AVCPanel::EFastForward; |
|
1531 break; |
|
1532 case ERemConCoreApiEject: |
|
1533 aAvrcpOp = AVCPanel::EEject; |
|
1534 break; |
|
1535 case ERemConCoreApiForward: |
|
1536 aAvrcpOp = AVCPanel::EForward; |
|
1537 break; |
|
1538 case ERemConCoreApiBackward: |
|
1539 aAvrcpOp = AVCPanel::EBackward; |
|
1540 break; |
|
1541 case ERemConCoreApiAngle: |
|
1542 aAvrcpOp = AVCPanel::EAngle; |
|
1543 break; |
|
1544 case ERemConCoreApiSubpicture: |
|
1545 aAvrcpOp = AVCPanel::ESubpicture; |
|
1546 break; |
|
1547 case ERemConCoreApiF1: |
|
1548 aAvrcpOp = AVCPanel::EF1; |
|
1549 break; |
|
1550 case ERemConCoreApiF2: |
|
1551 aAvrcpOp = AVCPanel::EF2; |
|
1552 break; |
|
1553 case ERemConCoreApiF3: |
|
1554 aAvrcpOp = AVCPanel::EF3; |
|
1555 break; |
|
1556 case ERemConCoreApiF4: |
|
1557 aAvrcpOp = AVCPanel::EF4; |
|
1558 break; |
|
1559 case ERemConCoreApiF5: |
|
1560 aAvrcpOp = AVCPanel::EF5; |
|
1561 break; |
|
1562 default: |
|
1563 err = KErrNotSupported; |
|
1564 } |
|
1565 return err; |
|
1566 } |
|
1567 |
|
1568 TUint16 CControlCommand::Get16(const TPtrC8& aPtr) |
|
1569 { |
|
1570 return (aPtr[0]<<8) | aPtr[1]; |
|
1571 } |
|
1572 |
|
1573 TInt CControlCommand::DummyCallback(TAny*) |
|
1574 { |
|
1575 // Should never be called- should be overwritten by a non-dummy callback |
|
1576 // before it's ever requested let alone called. |
|
1577 AvrcpUtils::Panic(EAvrcpDummyCallbackCalled); |
|
1578 return KErrNone; |
|
1579 } |
|
1580 |
|
1581 void CControlCommand::SetVendorInfoL(TBool aIsPassthrough) |
|
1582 { |
|
1583 if (aIsPassthrough) |
|
1584 { |
|
1585 if (iFrame->DataLength() < KAVCVendorUniquePassthroughHeader) |
|
1586 { |
|
1587 User::Leave(KErrCorrupt); |
|
1588 } |
|
1589 iVendorPayloadData.Set(CAVCVendorUniquePassthroughCommand::GetPayloadAndVID(*iFrame, iVendorId)); |
|
1590 } |
|
1591 else |
|
1592 { |
|
1593 if (iFrame->DataLength() < KAVCVendorIdLength) |
|
1594 { |
|
1595 User::Leave(KErrCorrupt); |
|
1596 } |
|
1597 iVendorPayloadData.Set(CAVCVendorDependentCommand::GetPayloadAndVID(*iFrame, iVendorId)); |
|
1598 } |
|
1599 } |
|
1600 |
|
1601 TBool CControlCommand::IsAvrcpPassthrough() const |
|
1602 { |
|
1603 TBool isAvrcpPassthrough = EFalse; |
|
1604 |
|
1605 if(iInterfaceUid.iUid == KRemConCoreApiUid || iInterfaceUid.iUid == KRemConGroupNavigationApiUid) |
|
1606 { |
|
1607 isAvrcpPassthrough = ETrue; |
|
1608 } |
|
1609 |
|
1610 return isAvrcpPassthrough; |
|
1611 } |
|
1612 |
|
1613 TBool CControlCommand::IsPassthrough() const |
|
1614 { |
|
1615 return ((iFrame->Opcode() == AVC::EPassThrough) && (iFrame->SubunitType() == AVC::EPanel)); |
|
1616 } |
|
1617 |
|
1618 TBool CControlCommand::PlayerSpecificNotify() const |
|
1619 { |
|
1620 TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId); |
|
1621 TMetadataTransferPDU pduId = RAvrcpIPC::GetPDUIdFromIPCOperationId(iOperationId); |
|
1622 |
|
1623 if(pduId != ERegisterNotification) |
|
1624 { |
|
1625 return EFalse; |
|
1626 } |
|
1627 |
|
1628 if(iInterfaceUid == TUid::Uid(KRemConPlayerInformationUid)) |
|
1629 { |
|
1630 if((eventId == ERegisterNotificationPlaybackStatusChanged) || |
|
1631 (eventId == ERegisterNotificationTrackChanged) || |
|
1632 (eventId == ERegisterNotificationTrackReachedEnd) || |
|
1633 (eventId == ERegisterNotificationTrackReachedStart) || |
|
1634 (eventId == ERegisterNotificationPlaybackPosChanged) || |
|
1635 (eventId == ERegisterNotificationPlayerApplicationSettingChanged)) |
|
1636 { |
|
1637 return ETrue; |
|
1638 } |
|
1639 } |
|
1640 else if(iInterfaceUid == TUid::Uid(KRemConNowPlayingApiUid)) |
|
1641 { |
|
1642 if (eventId == ERegisterNotificationNowPlayingContentChanged) |
|
1643 { |
|
1644 return ETrue; |
|
1645 } |
|
1646 } |
|
1647 else |
|
1648 { |
|
1649 return EFalse; |
|
1650 } |
|
1651 return EFalse; |
|
1652 } |
|
1653 |
|
1654 TBool CControlCommand::NormalCommand() |
|
1655 { |
|
1656 TBool ret = ETrue; |
|
1657 TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId); |
|
1658 TMetadataTransferPDU pduId = RAvrcpIPC::GetPDUIdFromIPCOperationId(iOperationId); |
|
1659 |
|
1660 if((eventId == ERegisterNotificationAvailablePlayersChanged) || |
|
1661 (eventId == ERegisterNotificationAddressedPlayerChanged)) |
|
1662 { |
|
1663 ret = EFalse; |
|
1664 } |
|
1665 return ret; |
|
1666 } |
|
1667 /** |
|
1668 @return Ownership of a CControlCommand representing an interim response to this command |
|
1669 */ |
|
1670 CControlCommand* CControlCommand::InterimResponseL() |
|
1671 { |
|
1672 CAVCFrame* frame = CAVCFrame::NewL(iFrame->Data(), AVC::EResponse); |
|
1673 CleanupStack::PushL(frame); |
|
1674 frame->SetType(AVC::EInterim); |
|
1675 |
|
1676 CControlCommand* finalResponse = CControlCommand::NewL(frame, iRemConId, |
|
1677 iTransactionLabel, iRemoteAddr, iClientId, iPlayerInfoManager); |
|
1678 CleanupStack::Pop(frame); |
|
1679 |
|
1680 finalResponse->iInterfaceUid = iInterfaceUid; |
|
1681 finalResponse->iOperationId = iOperationId; |
|
1682 |
|
1683 return finalResponse; |
|
1684 } |
|
1685 |