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 case KErrAvrcpHandledInternallyRespondNow: |
|
612 if (cType == AVC::EControl) |
|
613 { |
|
614 iFrame->SetType(AVC::EAccepted); |
|
615 } |
|
616 else if (cType == AVC::ENotify) |
|
617 { |
|
618 iFrame->SetType(AVC::EInterim); |
|
619 } |
|
620 else if (cType == AVC::EInterim) |
|
621 { |
|
622 iFrame->SetType(AVC::EChanged); |
|
623 } |
|
624 else if (cType == AVC::EStatus) |
|
625 { |
|
626 iFrame->SetType(AVC::EStable); |
|
627 } |
|
628 else |
|
629 { |
|
630 iFrame->SetType(AVC::EImplemented); |
|
631 } |
|
632 break; |
|
633 case KErrAvrcpMetadataInvalidCommand: |
|
634 case KErrAvrcpMetadataInvalidParameter: |
|
635 case KErrAvrcpMetadataParameterNotFound: |
|
636 case KErrAvrcpMetadataInternalError: |
|
637 case KErrAvrcpAirInvalidCommand: |
|
638 case KErrAvrcpAirInvalidParameter: |
|
639 case KErrAvrcpAirParameterNotFound: |
|
640 case KErrAvrcpAirInternalError: |
|
641 case KErrAvrcpAirSuccess: |
|
642 case KErrAvrcpAirUidChanged: |
|
643 case KErrAvrcpAirReserved: |
|
644 case KErrAvrcpAirInvalidDirection: |
|
645 case KErrAvrcpAirNotADirectory: |
|
646 case KErrAvrcpAirDoesNotExist: |
|
647 case KErrAvrcpAirInvalidScope: |
|
648 case KErrAvrcpAirRangeOutOfBounds: |
|
649 case KErrAvrcpAirUidIsADirectory: |
|
650 case KErrAvrcpAirMediaInUse: |
|
651 case KErrAvrcpAirNowPlayingListFull: |
|
652 case KErrAvrcpAirSearchNotSupported: |
|
653 case KErrAvrcpAirSearchInProgress: |
|
654 case KErrAvrcpAirInvalidPlayerId: |
|
655 case KErrAvrcpAirPlayerNotBrowesable: |
|
656 case KErrAvrcpAirPlayerNotAddressed: |
|
657 case KErrAvrcpAirNoValidSearchResults: |
|
658 case KErrAvrcpAirNoAvailablePlayers: |
|
659 case KErrAvrcpAirAddressedPlayerChanged: |
|
660 { |
|
661 // If this fails, we're OOM (it only contains a NewL) |
|
662 // so we can't send the error response - just give up |
|
663 TRAPD(err, GenerateMetadataRejectPayloadL(aErr)); |
|
664 err = err; // avoid warning about not using this |
|
665 break; |
|
666 } |
|
667 default: |
|
668 iFrame->SetType(AVC::ENotImplemented); |
|
669 } |
|
670 iFrame->SetFrameType(AVC::EResponse); |
|
671 } |
|
672 |
|
673 /** Gets this command's AV/C frame. |
|
674 @return the AV/C frame for this command |
|
675 */ |
|
676 const CAVCFrame& CControlCommand::Frame() const |
|
677 { |
|
678 LOG_FUNC |
|
679 return *iFrame; |
|
680 } |
|
681 |
|
682 const TDesC8& CControlCommand::Data() const |
|
683 { |
|
684 LOG_FUNC |
|
685 return iFrame->Data(); |
|
686 } |
|
687 |
|
688 SymbianAvctp::TMessageType CControlCommand::MessageType() const |
|
689 { |
|
690 LOG_FUNC |
|
691 return (iFrame->FrameType() == AVC::ECommand) ? SymbianAvctp::ECommand : SymbianAvctp::EResponse; |
|
692 } |
|
693 |
|
694 /** Gets the button action from this command's AV/C frame. |
|
695 This is only valid on passthrough commands. |
|
696 |
|
697 @return The button action. |
|
698 */ |
|
699 AVCPanel::TButtonAction CControlCommand::ButtonAct() const |
|
700 { |
|
701 LOG_FUNC |
|
702 AVCPanel::TButtonAction act; |
|
703 iFrame->ButtonAct(act); |
|
704 return act; |
|
705 } |
|
706 |
|
707 /** Gets whether this command is currently assumed to be a click. |
|
708 |
|
709 This is used to support the click facility offered by RemCon, which |
|
710 is not offered by AVRCP. As such AVRCP internally simulates outgoing |
|
711 clicks by generating a press and release for one RemCon click. When |
|
712 responses are received we know that if a command is a click we should |
|
713 send only one response up to RemCon. |
|
714 |
|
715 Incoming passthrough press commands are assumed to be click until |
|
716 the hold timer expires. When a matching release is received we can |
|
717 then tell whether we need to send a single click up to RemCon, or |
|
718 a release to match the press that was sent when the hold timer expired. |
|
719 |
|
720 @return ETrue is this is a click. EFalse if not. |
|
721 */ |
|
722 TBool CControlCommand::Click() const |
|
723 { |
|
724 LOG_FUNC |
|
725 return iIsClick; |
|
726 } |
|
727 |
|
728 /** Sets whether this command is currently assumed to be a click |
|
729 or not. |
|
730 |
|
731 @see CRcpcommand::Click() |
|
732 @param aIsClick ETrue to set this as click. EFalse to set this as |
|
733 not click. |
|
734 */ |
|
735 void CControlCommand::SetClick(TBool aIsClick) |
|
736 { |
|
737 LOG_FUNC |
|
738 iIsClick = aIsClick; |
|
739 } |
|
740 |
|
741 /** Sets the RemCon data to indicate what button action this |
|
742 command is. This function is only valid for commands in the |
|
743 core api. |
|
744 |
|
745 @param aButtonAct The RemCon button action for this command. |
|
746 @param aCommand Whether this is a command. This is needed |
|
747 because the command data is at a different offset for |
|
748 commands and responses. |
|
749 */ |
|
750 void CControlCommand::SetCoreButtonAction(TRemConCoreApiButtonAction aButtonAct, TBool aCommand) |
|
751 { |
|
752 LOG_FUNC |
|
753 |
|
754 TInt offset = aCommand ? KRemConCoreApiButtonDataOffset + KRemConCoreApiCommandDataOffset |
|
755 : KRemConCoreApiButtonDataOffset + KRemConCoreApiResponseDataOffset; |
|
756 |
|
757 AvrcpUtils::SetCommandDataFromInt(iCommandData, offset, |
|
758 KRemConCoreApiButtonDataLength, aButtonAct); |
|
759 } |
|
760 /** ReSets the RemCon data to indicate what button action this |
|
761 command is. This function is called when we the command is being re-used to generate a |
|
762 new command to remconServ. |
|
763 |
|
764 @param aButtonAct The RemCon button action for this command. |
|
765 @param aCommand Whether this is a command. This is needed |
|
766 because the command data is at a different offset for |
|
767 commands and responses. |
|
768 */ |
|
769 void CControlCommand::ReSetCoreButtonActionL(TRemConCoreApiButtonAction aButtonAct, TBool aCommand) |
|
770 { |
|
771 LOG_FUNC |
|
772 |
|
773 if (iCommandData.MaxLength() < KRemConCoreApiButtonDataLength) |
|
774 { |
|
775 iCommandData.Close(); |
|
776 iCommandData.CreateMaxL(KRemConCoreApiButtonDataLength); |
|
777 } |
|
778 |
|
779 SetCoreButtonAction(aButtonAct, aCommand); |
|
780 } |
|
781 |
|
782 /** Inserts the results at the beginning of this command's data. |
|
783 If the data buffer is not large enough it will be ReAlloced to |
|
784 allow the insertion. |
|
785 |
|
786 @return The result to pass to RemCon. KErrNone for an AV/C accepted. |
|
787 KErrNotSupported for an AV/C not implemented. KErrGeneral |
|
788 for an AV/C rejected. |
|
789 */ |
|
790 TInt CControlCommand::InsertCoreResult(TInt aResult) |
|
791 { |
|
792 LOG_FUNC |
|
793 TInt err = KErrNone; |
|
794 TInt requiredLength = KRemConCoreApiResultDataLength + iCommandData.Length(); |
|
795 |
|
796 if(iCommandData.Length() >= requiredLength) |
|
797 { |
|
798 // Insert data to write result into |
|
799 iCommandData.Insert(0, KRemConCoreApiResultPad); |
|
800 } |
|
801 else |
|
802 { |
|
803 // need longer buffer |
|
804 err = iCommandData.ReAlloc(requiredLength); |
|
805 if(!err) |
|
806 { |
|
807 iCommandData.Insert(0, KRemConCoreApiResultPad); |
|
808 } |
|
809 else |
|
810 { |
|
811 return err; |
|
812 } |
|
813 } |
|
814 |
|
815 AvrcpUtils::SetCommandDataFromInt(iCommandData, 0, |
|
816 KRemConCoreApiResultDataLength, aResult); |
|
817 return err; |
|
818 } |
|
819 |
|
820 /** |
|
821 Sets the result of set absolute volume response into this command's data |
|
822 */ |
|
823 TInt CControlCommand::SetSetAbsoluteVolumeResult(const CAVCFrame& aFrame) |
|
824 { |
|
825 TInt err = KErrNone; |
|
826 TRAP(err, DoSetAbsoluteVolumeResultL(aFrame)); |
|
827 if (err != KErrNone) |
|
828 { |
|
829 // Ensure the client can receive an error in case of |
|
830 // DoSetAbsoluteVolumeResultL leaves out. |
|
831 iCommandData.Zero(); |
|
832 TPckgBuf<TInt> errBuf(err); |
|
833 iCommandData.Append(errBuf); |
|
834 iCommandData.SetLength(iCommandData.MaxLength()); |
|
835 } |
|
836 return err; |
|
837 } |
|
838 |
|
839 void CControlCommand::DoSetAbsoluteVolumeResultL(const CAVCFrame& aFrame) |
|
840 { |
|
841 RRemConAbsoluteVolumeResponse absVol; |
|
842 absVol.iError = KErrGeneral; |
|
843 absVol.iMaxVolume = KAvrcpMaxAbsoluteVolume; |
|
844 |
|
845 CleanupClosePushL(absVol); |
|
846 |
|
847 switch(aFrame.Type()) |
|
848 { |
|
849 case AVC::EAccepted: |
|
850 { |
|
851 if (aFrame.Data().Length() == KLengthSetAbsoluteVolumeResponse) |
|
852 { |
|
853 absVol.iError = KErrNone; |
|
854 TUint volumeOffset = KLengthSetAbsoluteVolumeResponse - 1; |
|
855 absVol.iVolume = KAbsoluteVolumeMask & aFrame.Data()[volumeOffset]; |
|
856 } |
|
857 break; |
|
858 } |
|
859 case AVC::ERejected: // fall through |
|
860 case AVC::ENotImplemented: |
|
861 break; |
|
862 default: |
|
863 break; |
|
864 } |
|
865 |
|
866 absVol.WriteL(iCommandData); |
|
867 CleanupStack::PopAndDestroy(&absVol); |
|
868 } |
|
869 /** |
|
870 Sets the result of volume changed notification response into this command's |
|
871 data. |
|
872 */ |
|
873 TInt CControlCommand::SetNotifyVolumeChangeResult(const CAVCFrame& aFrame) |
|
874 { |
|
875 TInt err = KErrNone; |
|
876 TRAP(err, DoSetNotifyVolumeChangeResultL(aFrame)); |
|
877 if (err == KErrNone) |
|
878 { |
|
879 // Through AVC::TCType the RemCon sever can know whether the response |
|
880 // is an Interim or Changed or any other responses, so the RemCon |
|
881 // server can decide to remove the notify command from its |
|
882 // outgoingsent queue or not. |
|
883 iFrame->SetType(aFrame.Type()); |
|
884 } |
|
885 else |
|
886 { |
|
887 // Ensure the client can receive an error in case of |
|
888 // DoSetNotifyVolumeChangeResultL leaves out. |
|
889 iCommandData.Zero(); |
|
890 TPckgBuf<TInt> errBuf(KErrGeneral); |
|
891 iCommandData.Append(errBuf); |
|
892 iCommandData.SetLength(iCommandData.MaxLength()); |
|
893 |
|
894 // Setting AVC::TCType to ERejected is intended to let the RemCon |
|
895 // server to remove the notify command from its outgoingsent queue |
|
896 // in case of DoSetNotifyVolumeChangeResultL leaves out. |
|
897 iFrame->SetType(AVC::ERejected); |
|
898 } |
|
899 |
|
900 return err; |
|
901 } |
|
902 |
|
903 void CControlCommand::DoSetNotifyVolumeChangeResultL(const CAVCFrame& aFrame) |
|
904 { |
|
905 if (iCommandData.MaxLength() < KAbsoluteVolumeResponseDataSize) |
|
906 { |
|
907 iCommandData.Close(); |
|
908 iCommandData.CreateL(KAbsoluteVolumeResponseDataSize); |
|
909 } |
|
910 |
|
911 RRemConAbsoluteVolumeResponse absVol; |
|
912 absVol.iError = KErrGeneral; |
|
913 absVol.iMaxVolume = KAvrcpMaxAbsoluteVolume; |
|
914 |
|
915 CleanupClosePushL(absVol); |
|
916 |
|
917 switch(aFrame.Type()) |
|
918 { |
|
919 case AVC::EInterim: |
|
920 case AVC::EChanged: |
|
921 { |
|
922 if (aFrame.Data().Length() == KLengthNotifyVolumeChangeResponse) |
|
923 { |
|
924 absVol.iError = KErrNone; |
|
925 TUint volumeOffset = KLengthNotifyVolumeChangeResponse - 1; |
|
926 absVol.iVolume = KAbsoluteVolumeMask & aFrame.Data()[volumeOffset]; |
|
927 } |
|
928 break; |
|
929 } |
|
930 case AVC::ERejected: // fall through |
|
931 case AVC::ENotImplemented: |
|
932 break; |
|
933 default: |
|
934 break; |
|
935 } |
|
936 absVol.WriteL(iCommandData); |
|
937 CleanupStack::PopAndDestroy(&absVol); |
|
938 } |
|
939 //------------------------------------------------------------------------------------ |
|
940 // Internal utility functions |
|
941 //------------------------------------------------------------------------------------ |
|
942 |
|
943 /** Fills in command info from an AVC Control. |
|
944 |
|
945 This functions sets iInterfaceUid, iOperationId and iCommandData |
|
946 to the correct values according to iFrame. The format of iCommandData |
|
947 is defined by RemCon and is dependent on iInterfaceUid and iOperationId. |
|
948 |
|
949 @return KErrNone If the frame has been parsed successfully. |
|
950 @return KErrNotSupported This frame represents a command for which a |
|
951 RemCon converter or client side interface |
|
952 cannot be found. |
|
953 @return System wide error code. |
|
954 */ |
|
955 TInt CControlCommand::ParseIncomingKnownOpcodeL(MRemConBearerObserver& aObserver) |
|
956 { |
|
957 LOG_FUNC |
|
958 TInt err = KErrNotSupported; |
|
959 |
|
960 AVC::TCType cType = iFrame->Type(); |
|
961 |
|
962 switch(iFrame->Opcode()) |
|
963 { |
|
964 case AVC::EPassThrough: |
|
965 { |
|
966 if(iFrame->Data().Length() < KAVCPassthroughFrameLength) |
|
967 { |
|
968 LEAVEL(KErrCorrupt); |
|
969 } |
|
970 if (iFrame->SubunitType() != AVC::EPanel) |
|
971 { |
|
972 LEAVEL(KErrNotSupported); |
|
973 } |
|
974 |
|
975 TUint8 avrcpOp; |
|
976 if (cType != AVC::EGeneralEnquiry && cType == AVC::EControl) |
|
977 { |
|
978 iCommandData.CreateMaxL(KRemConCoreApiButtonDataLength); |
|
979 err = iFrame->OperationId(avrcpOp); |
|
980 if (err == KErrNone) |
|
981 { |
|
982 if (avrcpOp!=AVCPanel::EVendorUnique) |
|
983 { |
|
984 err = AvrcpToRemConOperation(avrcpOp, iOperationId, iInterfaceUid); |
|
985 } |
|
986 else |
|
987 { |
|
988 err = ParseVendorUniquePassthroughCommand(aObserver); |
|
989 } |
|
990 } |
|
991 |
|
992 if (err!=KErrNone) |
|
993 { |
|
994 err = KErrAvrcpInvalidOperationId; |
|
995 } |
|
996 } |
|
997 else |
|
998 { |
|
999 iCommandData.Close(); |
|
1000 iCommandData.CreateL(KAVCFrameMaxLength); |
|
1001 TRemConMessageType message = ERemConCommand; |
|
1002 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1003 iFrame->Data(), |
|
1004 iFrame->Data(), |
|
1005 iInterfaceUid, |
|
1006 iOperationId, |
|
1007 message, |
|
1008 iCommandData); |
|
1009 } |
|
1010 break; |
|
1011 } |
|
1012 case AVC::EUnitInfo: |
|
1013 { |
|
1014 if (iFrame->Type() == AVC::EStatus) |
|
1015 { |
|
1016 CAVCFrame* resp = AvrcpCommandFramer::UnitInfoResponseL(); |
|
1017 delete iFrame; |
|
1018 iFrame = resp; |
|
1019 err = KErrCompletion; // since bearer has done its job without client needed |
|
1020 } |
|
1021 else |
|
1022 { |
|
1023 err = KErrAvrcpInvalidCType; |
|
1024 } |
|
1025 break; |
|
1026 } |
|
1027 case AVC::ESubunitInfo: |
|
1028 { |
|
1029 if (iFrame->Type() == AVC::EStatus) |
|
1030 { |
|
1031 CAVCFrame* resp = AvrcpCommandFramer::SubunitInfoResponseL(); |
|
1032 delete iFrame; |
|
1033 iFrame = resp; |
|
1034 err = KErrCompletion; // since bearer has done its job without client needed |
|
1035 } |
|
1036 else |
|
1037 { |
|
1038 err = KErrAvrcpInvalidCType; |
|
1039 } |
|
1040 break; |
|
1041 } |
|
1042 |
|
1043 default: |
|
1044 { |
|
1045 iCommandData.Close(); |
|
1046 iCommandData.CreateL(KAVCFrameMaxLength); |
|
1047 TRemConMessageType message = ERemConCommand; |
|
1048 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1049 iFrame->Data(), |
|
1050 iFrame->Data(), |
|
1051 iInterfaceUid, |
|
1052 iOperationId, |
|
1053 message, |
|
1054 iCommandData); |
|
1055 break; |
|
1056 } |
|
1057 } |
|
1058 |
|
1059 return err; |
|
1060 } |
|
1061 |
|
1062 |
|
1063 /** Fills in command info from an AVC Vendor Dependent message. |
|
1064 |
|
1065 This functions sets iInterfaceUid, iOperationId and iCommandData |
|
1066 to the correct values according to iFrame. The format of iCommandData |
|
1067 is defined by RemCon and is dependent on iInterfaceUid and iOperationId. |
|
1068 The AVC frame's length is checked that it at least contains the vendor id. |
|
1069 |
|
1070 @param aObserver An observer to be used to obtain a converter. |
|
1071 @return KErrNone If the frame has been parsed successfully. |
|
1072 @return KErrNotSupported This frame represents a command for which a |
|
1073 RemCon converter or client side interface |
|
1074 cannot be found. |
|
1075 @return KErrAvrcpInvalidCType The CType specified in this frame is invalid. |
|
1076 @return KErrAvrcpMetadataInvalidCommand The AVRCP command is invalid. |
|
1077 @return KErrAvrcpMetadataInvalidParameter The AVRCP parameter is invalid. |
|
1078 @return KErrAvrcpMetadataParameterNotFound The AVRCP parameter was not found. |
|
1079 @return KErrAvrcpMetadataInternalError An AVRCP internal error occurred (such as out-of-memory, |
|
1080 or an inter-process communication error) |
|
1081 @return System wide error code. |
|
1082 */ |
|
1083 TInt CControlCommand::ParseIncomingVendorCommandL(MRemConBearerObserver& aObserver, CAVRCPFragmenter& aFragmenter) |
|
1084 { |
|
1085 LOG_FUNC |
|
1086 TInt err = KErrNone; |
|
1087 |
|
1088 SetVendorInfoL(EFalse); // set id and payload; leaves if not enough space available |
|
1089 |
|
1090 if (iVendorId!=KBluetoothSIGVendorId) |
|
1091 { |
|
1092 iCommandData.Close(); |
|
1093 iCommandData.CreateL(KAVCFrameMaxLength); |
|
1094 |
|
1095 TRemConMessageType message = ERemConCommand; |
|
1096 |
|
1097 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1098 iFrame->Data(), |
|
1099 iFrame->Data(), |
|
1100 iInterfaceUid, |
|
1101 iOperationId, |
|
1102 message, |
|
1103 iCommandData); |
|
1104 } |
|
1105 else |
|
1106 { |
|
1107 // process v>1.0 version of AVRCP |
|
1108 // which use vendor dependent frames to extend v1.0 of AVRCP |
|
1109 // the vendor code has the value for the BT SIG |
|
1110 if (iFrame->SubunitType() != AVC::EPanel) |
|
1111 { |
|
1112 // this is for Control not Metadata |
|
1113 return KErrNotSupported; |
|
1114 } |
|
1115 |
|
1116 err = ParseMetadataTransferVendorCommand(aFragmenter); |
|
1117 if (err == KErrNone) |
|
1118 { |
|
1119 // Check that the interface UID is non-zero |
|
1120 __ASSERT_DEBUG(iInterfaceUid != TUid::Uid(0), AvrcpUtils::Panic(EAvrcpInterfaceUidNotSet)); |
|
1121 } |
|
1122 } |
|
1123 return err; |
|
1124 } |
|
1125 |
|
1126 |
|
1127 /** Creates RemCon command information from iFrame. |
|
1128 |
|
1129 This functions sets iInterfaceUid, iOperationId and iCommandData |
|
1130 to the correct values according to iFrame. The format of iCommandData |
|
1131 is defined by the interface, iInterfaceUid and is dependent on |
|
1132 iOperationId. A converter should be able to be found as this response |
|
1133 is a result of an outgoing command on this interface. |
|
1134 |
|
1135 @param aObserver An observer used to get a converter. |
|
1136 @param aFrame The AV/C frame for this command. |
|
1137 */ |
|
1138 void CControlCommand::ParseIncomingUnknownResponse(MRemConBearerObserver& aObserver, |
|
1139 const CAVCFrame& aFrame) |
|
1140 { |
|
1141 LOG_FUNC |
|
1142 // We need to pass a response up to RemCon even if we can't get a |
|
1143 // converter to generate a decent response so we don't |
|
1144 |
|
1145 iCommandData.Close(); |
|
1146 TInt err = iCommandData.Create(KAVCFrameMaxLength); |
|
1147 if(!err) |
|
1148 { |
|
1149 TRemConMessageType type = ERemConResponse; // output param |
|
1150 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1151 aFrame.Data(), aFrame.Data(), iInterfaceUid, iOperationId, type, iCommandData); |
|
1152 } |
|
1153 } |
|
1154 |
|
1155 /** Translates from an AVC operation id to RemCon's core interface. |
|
1156 |
|
1157 @param aAvrcpOp The AVC passthrough operation id. |
|
1158 @param aRemConOp On return the RemCon operation id within the core interface. |
|
1159 @return KErrNone If the operation has been translated successfully. |
|
1160 @return KErrNotSupported If the operation does not correspond to one |
|
1161 in the RemCon core interface. |
|
1162 */ |
|
1163 TInt CControlCommand::AvrcpToRemConOperation(TUint aAvrcpOp, TUint& aRemConOp, TUid& aRemConIf) |
|
1164 { |
|
1165 LOG_STATIC_FUNC |
|
1166 TInt err = KErrNone; |
|
1167 |
|
1168 //TBH setting here as most are for the Core API |
|
1169 //some cases will override |
|
1170 aRemConIf = TUid::Uid(KRemConCoreApiUid); |
|
1171 |
|
1172 switch(aAvrcpOp) |
|
1173 { |
|
1174 case AVCPanel::ESelect: |
|
1175 aRemConOp = ERemConCoreApiSelect; |
|
1176 break; |
|
1177 case AVCPanel::EUp: |
|
1178 aRemConOp = ERemConCoreApiUp; |
|
1179 break; |
|
1180 case AVCPanel::EDown: |
|
1181 aRemConOp = ERemConCoreApiDown; |
|
1182 break; |
|
1183 case AVCPanel::ELeft: |
|
1184 aRemConOp = ERemConCoreApiLeft; |
|
1185 break; |
|
1186 case AVCPanel::ERight: |
|
1187 aRemConOp = ERemConCoreApiRight; |
|
1188 break; |
|
1189 case AVCPanel::ERightUp: |
|
1190 aRemConOp = ERemConCoreApiRightUp; |
|
1191 break; |
|
1192 case AVCPanel::ERightDown: |
|
1193 aRemConOp = ERemConCoreApiRightDown; |
|
1194 break; |
|
1195 case AVCPanel::ELeftUp: |
|
1196 aRemConOp = ERemConCoreApiLeftUp; |
|
1197 break; |
|
1198 case AVCPanel::ELeftDown: |
|
1199 aRemConOp = ERemConCoreApiLeftDown; |
|
1200 break; |
|
1201 case AVCPanel::ERootMenu: |
|
1202 aRemConOp = ERemConCoreApiRootMenu; |
|
1203 break; |
|
1204 case AVCPanel::ESetupMenu: |
|
1205 aRemConOp = ERemConCoreApiSetupMenu; |
|
1206 break; |
|
1207 case AVCPanel::EContentsMenu: |
|
1208 aRemConOp = ERemConCoreApiContentsMenu; |
|
1209 break; |
|
1210 case AVCPanel::EFavoriteMenu: |
|
1211 aRemConOp = ERemConCoreApiFavoriteMenu; |
|
1212 break; |
|
1213 case AVCPanel::EExit: |
|
1214 aRemConOp = ERemConCoreApiExit; |
|
1215 break; |
|
1216 case AVCPanel::E0: |
|
1217 aRemConOp = ERemConCoreApi0; |
|
1218 break; |
|
1219 case AVCPanel::E1: |
|
1220 aRemConOp = ERemConCoreApi1; |
|
1221 break; |
|
1222 case AVCPanel::E2: |
|
1223 aRemConOp = ERemConCoreApi2; |
|
1224 break; |
|
1225 case AVCPanel::E3: |
|
1226 aRemConOp = ERemConCoreApi3; |
|
1227 break; |
|
1228 case AVCPanel::E4: |
|
1229 aRemConOp = ERemConCoreApi4; |
|
1230 break; |
|
1231 case AVCPanel::E5: |
|
1232 aRemConOp = ERemConCoreApi5; |
|
1233 break; |
|
1234 case AVCPanel::E6: |
|
1235 aRemConOp = ERemConCoreApi6; |
|
1236 break; |
|
1237 case AVCPanel::E7: |
|
1238 aRemConOp = ERemConCoreApi7; |
|
1239 break; |
|
1240 case AVCPanel::E8: |
|
1241 aRemConOp = ERemConCoreApi8; |
|
1242 break; |
|
1243 case AVCPanel::E9: |
|
1244 aRemConOp = ERemConCoreApi9; |
|
1245 break; |
|
1246 case AVCPanel::EDot: |
|
1247 aRemConOp = ERemConCoreApiDot; |
|
1248 break; |
|
1249 case AVCPanel::EEnter: |
|
1250 aRemConOp = ERemConCoreApiEnter; |
|
1251 break; |
|
1252 case AVCPanel::EClear: |
|
1253 aRemConOp = ERemConCoreApiClear; |
|
1254 break; |
|
1255 case AVCPanel::EChannelUp: |
|
1256 aRemConOp = ERemConCoreApiChannelUp; |
|
1257 break; |
|
1258 case AVCPanel::EChannelDown: |
|
1259 aRemConOp = ERemConCoreApiChannelDown; |
|
1260 break; |
|
1261 case AVCPanel::EPreviousChannel: |
|
1262 aRemConOp = ERemConCoreApiPreviousChannel; |
|
1263 break; |
|
1264 case AVCPanel::ESoundSelect: |
|
1265 aRemConOp = ERemConCoreApiSoundSelect; |
|
1266 break; |
|
1267 case AVCPanel::EInputSelect: |
|
1268 aRemConOp = ERemConCoreApiInputSelect; |
|
1269 break; |
|
1270 case AVCPanel::EDisplayInformation: |
|
1271 aRemConOp = ERemConCoreApiDisplayInformation; |
|
1272 break; |
|
1273 case AVCPanel::EHelp: |
|
1274 aRemConOp = ERemConCoreApiHelp; |
|
1275 break; |
|
1276 case AVCPanel::EPageUp: |
|
1277 aRemConOp = ERemConCoreApiPageUp; |
|
1278 break; |
|
1279 case AVCPanel::EPageDown: |
|
1280 aRemConOp = ERemConCoreApiPageDown; |
|
1281 break; |
|
1282 case AVCPanel::EPower: |
|
1283 aRemConOp = ERemConCoreApiPower; |
|
1284 break; |
|
1285 case AVCPanel::EVolumeUp: |
|
1286 aRemConOp = ERemConCoreApiVolumeUp; |
|
1287 break; |
|
1288 case AVCPanel::EVolumeDown: |
|
1289 aRemConOp = ERemConCoreApiVolumeDown; |
|
1290 break; |
|
1291 case AVCPanel::EMute: |
|
1292 aRemConOp = ERemConCoreApiMute; |
|
1293 break; |
|
1294 case AVCPanel::EPlay: |
|
1295 aRemConOp = ERemConCoreApiPlay; |
|
1296 break; |
|
1297 case AVCPanel::EStop: |
|
1298 aRemConOp = ERemConCoreApiStop; |
|
1299 break; |
|
1300 case AVCPanel::EPause: |
|
1301 aRemConOp = ERemConCoreApiPause; |
|
1302 break; |
|
1303 case AVCPanel::ERecord: |
|
1304 aRemConOp = ERemConCoreApiRecord; |
|
1305 break; |
|
1306 case AVCPanel::ERewind: |
|
1307 aRemConOp = ERemConCoreApiRewind; |
|
1308 break; |
|
1309 case AVCPanel::EFastForward: |
|
1310 aRemConOp = ERemConCoreApiFastForward; |
|
1311 break; |
|
1312 case AVCPanel::EEject: |
|
1313 aRemConOp = ERemConCoreApiEject; |
|
1314 break; |
|
1315 case AVCPanel::EForward: |
|
1316 aRemConOp = ERemConCoreApiForward; |
|
1317 break; |
|
1318 case AVCPanel::EBackward: |
|
1319 aRemConOp = ERemConCoreApiBackward; |
|
1320 break; |
|
1321 case AVCPanel::EAngle: |
|
1322 aRemConOp = ERemConCoreApiAngle; |
|
1323 break; |
|
1324 case AVCPanel::ESubpicture: |
|
1325 aRemConOp = ERemConCoreApiSubpicture; |
|
1326 break; |
|
1327 case AVCPanel::EF1: |
|
1328 aRemConOp = ERemConCoreApiF1; |
|
1329 break; |
|
1330 case AVCPanel::EF2: |
|
1331 aRemConOp = ERemConCoreApiF2; |
|
1332 break; |
|
1333 case AVCPanel::EF3: |
|
1334 aRemConOp = ERemConCoreApiF3; |
|
1335 break; |
|
1336 case AVCPanel::EF4: |
|
1337 aRemConOp = ERemConCoreApiF4; |
|
1338 break; |
|
1339 case AVCPanel::EF5: |
|
1340 aRemConOp = ERemConCoreApiF5; |
|
1341 break; |
|
1342 case AVCPanel::EVendorUnique: |
|
1343 default: |
|
1344 err = KErrNotSupported; |
|
1345 } |
|
1346 |
|
1347 return err; |
|
1348 } |
|
1349 |
|
1350 |
|
1351 TInt CControlCommand::ParseVendorUniquePassthroughCommand(MRemConBearerObserver& aObserver) |
|
1352 { |
|
1353 TInt err = KErrNone; |
|
1354 TRAP(err, SetVendorInfoL(ETrue)); // set id and payload; leaves if not enough space available |
|
1355 |
|
1356 if (err == KErrNone && iVendorId == KBluetoothSIGVendorId) |
|
1357 { |
|
1358 // it's one of the v1.3 (or later!) MT commands |
|
1359 err = ParseMetadataTransferPassthroughCommand(); |
|
1360 } |
|
1361 else |
|
1362 { |
|
1363 iCommandData.Close(); |
|
1364 TRAP(err, iCommandData.CreateL(KAVCFrameMaxLength)); |
|
1365 if(err == KErrNone) |
|
1366 { |
|
1367 TRemConMessageType message = ERemConCommand; |
|
1368 err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid), |
|
1369 iFrame->Data(), |
|
1370 iFrame->Data(), |
|
1371 iInterfaceUid, |
|
1372 iOperationId, |
|
1373 message, |
|
1374 iCommandData); |
|
1375 } |
|
1376 } |
|
1377 |
|
1378 return err; |
|
1379 } |
|
1380 |
|
1381 /** Translates from RemCon's core interface to an AVC operation id. |
|
1382 |
|
1383 @param aRemConOp The RemCon operation id within the core interface. |
|
1384 @param aAvrcpOp On return the AVC passthrough operation id. |
|
1385 @return KErrNone If the operation has been translated successfully. |
|
1386 @return KErrNotSupported If the operation does not correspond to one |
|
1387 provided by AVRCP. |
|
1388 */ |
|
1389 TInt CControlCommand::RemConToAvrcpOperation(TUint aRemConOp, AVCPanel::TOperationId& aAvrcpOp) |
|
1390 { |
|
1391 LOG_STATIC_FUNC |
|
1392 TInt err = KErrNone; |
|
1393 switch(aRemConOp) |
|
1394 { |
|
1395 case ERemConCoreApiSelect: |
|
1396 aAvrcpOp = AVCPanel::ESelect; |
|
1397 break; |
|
1398 case ERemConCoreApiUp: |
|
1399 aAvrcpOp = AVCPanel::EUp; |
|
1400 break; |
|
1401 case ERemConCoreApiDown: |
|
1402 aAvrcpOp = AVCPanel::EDown; |
|
1403 break; |
|
1404 case ERemConCoreApiLeft: |
|
1405 aAvrcpOp = AVCPanel::ELeft; |
|
1406 break; |
|
1407 case ERemConCoreApiRight: |
|
1408 aAvrcpOp = AVCPanel::ERight; |
|
1409 break; |
|
1410 case ERemConCoreApiRightUp: |
|
1411 aAvrcpOp = AVCPanel::ERightUp; |
|
1412 break; |
|
1413 case ERemConCoreApiRightDown: |
|
1414 aAvrcpOp = AVCPanel::ERightDown; |
|
1415 break; |
|
1416 case ERemConCoreApiLeftUp: |
|
1417 aAvrcpOp = AVCPanel::ELeftUp; |
|
1418 break; |
|
1419 case ERemConCoreApiLeftDown: |
|
1420 aAvrcpOp = AVCPanel::ELeftDown; |
|
1421 break; |
|
1422 case ERemConCoreApiRootMenu: |
|
1423 aAvrcpOp = AVCPanel::ERootMenu; |
|
1424 break; |
|
1425 case ERemConCoreApiSetupMenu: |
|
1426 aAvrcpOp = AVCPanel::ESetupMenu; |
|
1427 break; |
|
1428 case ERemConCoreApiContentsMenu: |
|
1429 aAvrcpOp = AVCPanel::EContentsMenu; |
|
1430 break; |
|
1431 case ERemConCoreApiFavoriteMenu: |
|
1432 aAvrcpOp = AVCPanel::EFavoriteMenu; |
|
1433 break; |
|
1434 case ERemConCoreApiExit: |
|
1435 aAvrcpOp = AVCPanel::EExit; |
|
1436 break; |
|
1437 case ERemConCoreApi0: |
|
1438 aAvrcpOp = AVCPanel::E0; |
|
1439 break; |
|
1440 case ERemConCoreApi1: |
|
1441 aAvrcpOp = AVCPanel::E1; |
|
1442 break; |
|
1443 case ERemConCoreApi2: |
|
1444 aAvrcpOp = AVCPanel::E2; |
|
1445 break; |
|
1446 case ERemConCoreApi3: |
|
1447 aAvrcpOp = AVCPanel::E3; |
|
1448 break; |
|
1449 case ERemConCoreApi4: |
|
1450 aAvrcpOp = AVCPanel::E4; |
|
1451 break; |
|
1452 case ERemConCoreApi5: |
|
1453 aAvrcpOp = AVCPanel::E5; |
|
1454 break; |
|
1455 case ERemConCoreApi6: |
|
1456 aAvrcpOp = AVCPanel::E6; |
|
1457 break; |
|
1458 case ERemConCoreApi7: |
|
1459 aAvrcpOp = AVCPanel::E7; |
|
1460 break; |
|
1461 case ERemConCoreApi8: |
|
1462 aAvrcpOp = AVCPanel::E8; |
|
1463 break; |
|
1464 case ERemConCoreApi9: |
|
1465 aAvrcpOp = AVCPanel::E9; |
|
1466 break; |
|
1467 case ERemConCoreApiDot: |
|
1468 aAvrcpOp = AVCPanel::EDot; |
|
1469 break; |
|
1470 case ERemConCoreApiEnter: |
|
1471 aAvrcpOp = AVCPanel::EEnter; |
|
1472 break; |
|
1473 case ERemConCoreApiClear: |
|
1474 aAvrcpOp = AVCPanel::EClear; |
|
1475 break; |
|
1476 case ERemConCoreApiChannelUp: |
|
1477 aAvrcpOp = AVCPanel::EChannelUp; |
|
1478 break; |
|
1479 case ERemConCoreApiChannelDown: |
|
1480 aAvrcpOp = AVCPanel::EChannelDown; |
|
1481 break; |
|
1482 case ERemConCoreApiPreviousChannel: |
|
1483 aAvrcpOp = AVCPanel::EPreviousChannel; |
|
1484 break; |
|
1485 case ERemConCoreApiSoundSelect: |
|
1486 aAvrcpOp = AVCPanel::ESoundSelect; |
|
1487 break; |
|
1488 case ERemConCoreApiInputSelect: |
|
1489 aAvrcpOp = AVCPanel::EInputSelect; |
|
1490 break; |
|
1491 case ERemConCoreApiDisplayInformation: |
|
1492 aAvrcpOp = AVCPanel::EDisplayInformation; |
|
1493 break; |
|
1494 case ERemConCoreApiHelp: |
|
1495 aAvrcpOp = AVCPanel::EHelp; |
|
1496 break; |
|
1497 case ERemConCoreApiPageUp: |
|
1498 aAvrcpOp = AVCPanel::EPageUp; |
|
1499 break; |
|
1500 case ERemConCoreApiPageDown: |
|
1501 aAvrcpOp = AVCPanel::EPageDown; |
|
1502 break; |
|
1503 case ERemConCoreApiPower: |
|
1504 aAvrcpOp = AVCPanel::EPower; |
|
1505 break; |
|
1506 case ERemConCoreApiVolumeUp: |
|
1507 aAvrcpOp = AVCPanel::EVolumeUp; |
|
1508 break; |
|
1509 case ERemConCoreApiVolumeDown: |
|
1510 aAvrcpOp = AVCPanel::EVolumeDown; |
|
1511 break; |
|
1512 case ERemConCoreApiMute: |
|
1513 aAvrcpOp = AVCPanel::EMute; |
|
1514 break; |
|
1515 case ERemConCoreApiPlay: |
|
1516 aAvrcpOp = AVCPanel::EPlay; |
|
1517 break; |
|
1518 case ERemConCoreApiStop: |
|
1519 aAvrcpOp = AVCPanel::EStop; |
|
1520 break; |
|
1521 case ERemConCoreApiPause: |
|
1522 aAvrcpOp = AVCPanel::EPause; |
|
1523 break; |
|
1524 case ERemConCoreApiRecord: |
|
1525 aAvrcpOp = AVCPanel::ERecord; |
|
1526 break; |
|
1527 case ERemConCoreApiRewind: |
|
1528 aAvrcpOp = AVCPanel::ERewind; |
|
1529 break; |
|
1530 case ERemConCoreApiFastForward: |
|
1531 aAvrcpOp = AVCPanel::EFastForward; |
|
1532 break; |
|
1533 case ERemConCoreApiEject: |
|
1534 aAvrcpOp = AVCPanel::EEject; |
|
1535 break; |
|
1536 case ERemConCoreApiForward: |
|
1537 aAvrcpOp = AVCPanel::EForward; |
|
1538 break; |
|
1539 case ERemConCoreApiBackward: |
|
1540 aAvrcpOp = AVCPanel::EBackward; |
|
1541 break; |
|
1542 case ERemConCoreApiAngle: |
|
1543 aAvrcpOp = AVCPanel::EAngle; |
|
1544 break; |
|
1545 case ERemConCoreApiSubpicture: |
|
1546 aAvrcpOp = AVCPanel::ESubpicture; |
|
1547 break; |
|
1548 case ERemConCoreApiF1: |
|
1549 aAvrcpOp = AVCPanel::EF1; |
|
1550 break; |
|
1551 case ERemConCoreApiF2: |
|
1552 aAvrcpOp = AVCPanel::EF2; |
|
1553 break; |
|
1554 case ERemConCoreApiF3: |
|
1555 aAvrcpOp = AVCPanel::EF3; |
|
1556 break; |
|
1557 case ERemConCoreApiF4: |
|
1558 aAvrcpOp = AVCPanel::EF4; |
|
1559 break; |
|
1560 case ERemConCoreApiF5: |
|
1561 aAvrcpOp = AVCPanel::EF5; |
|
1562 break; |
|
1563 default: |
|
1564 err = KErrNotSupported; |
|
1565 } |
|
1566 return err; |
|
1567 } |
|
1568 |
|
1569 TUint16 CControlCommand::Get16(const TPtrC8& aPtr) |
|
1570 { |
|
1571 return (aPtr[0]<<8) | aPtr[1]; |
|
1572 } |
|
1573 |
|
1574 TInt CControlCommand::DummyCallback(TAny*) |
|
1575 { |
|
1576 // Should never be called- should be overwritten by a non-dummy callback |
|
1577 // before it's ever requested let alone called. |
|
1578 AvrcpUtils::Panic(EAvrcpDummyCallbackCalled); |
|
1579 return KErrNone; |
|
1580 } |
|
1581 |
|
1582 void CControlCommand::SetVendorInfoL(TBool aIsPassthrough) |
|
1583 { |
|
1584 if (aIsPassthrough) |
|
1585 { |
|
1586 if (iFrame->DataLength() < KAVCVendorUniquePassthroughHeader) |
|
1587 { |
|
1588 User::Leave(KErrCorrupt); |
|
1589 } |
|
1590 iVendorPayloadData.Set(CAVCVendorUniquePassthroughCommand::GetPayloadAndVID(*iFrame, iVendorId)); |
|
1591 } |
|
1592 else |
|
1593 { |
|
1594 if (iFrame->DataLength() < KAVCVendorIdLength) |
|
1595 { |
|
1596 User::Leave(KErrCorrupt); |
|
1597 } |
|
1598 iVendorPayloadData.Set(CAVCVendorDependentCommand::GetPayloadAndVID(*iFrame, iVendorId)); |
|
1599 } |
|
1600 } |
|
1601 |
|
1602 TBool CControlCommand::IsAvrcpPassthrough() const |
|
1603 { |
|
1604 TBool isAvrcpPassthrough = EFalse; |
|
1605 |
|
1606 if(iInterfaceUid.iUid == KRemConCoreApiUid || iInterfaceUid.iUid == KRemConGroupNavigationApiUid) |
|
1607 { |
|
1608 isAvrcpPassthrough = ETrue; |
|
1609 } |
|
1610 |
|
1611 return isAvrcpPassthrough; |
|
1612 } |
|
1613 |
|
1614 TBool CControlCommand::IsPassthrough() const |
|
1615 { |
|
1616 return ((iFrame->Opcode() == AVC::EPassThrough) && (iFrame->SubunitType() == AVC::EPanel)); |
|
1617 } |
|
1618 |
|
1619 TBool CControlCommand::PlayerSpecificNotify() const |
|
1620 { |
|
1621 TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId); |
|
1622 TMetadataTransferPDU pduId = RAvrcpIPC::GetPDUIdFromIPCOperationId(iOperationId); |
|
1623 |
|
1624 if(pduId != ERegisterNotification) |
|
1625 { |
|
1626 return EFalse; |
|
1627 } |
|
1628 |
|
1629 if(iInterfaceUid == TUid::Uid(KRemConPlayerInformationUid)) |
|
1630 { |
|
1631 if((eventId == ERegisterNotificationPlaybackStatusChanged) || |
|
1632 (eventId == ERegisterNotificationTrackChanged) || |
|
1633 (eventId == ERegisterNotificationTrackReachedEnd) || |
|
1634 (eventId == ERegisterNotificationTrackReachedStart) || |
|
1635 (eventId == ERegisterNotificationPlaybackPosChanged) || |
|
1636 (eventId == ERegisterNotificationPlayerApplicationSettingChanged)) |
|
1637 { |
|
1638 return ETrue; |
|
1639 } |
|
1640 } |
|
1641 else if(iInterfaceUid == TUid::Uid(KRemConNowPlayingApiUid)) |
|
1642 { |
|
1643 if (eventId == ERegisterNotificationNowPlayingContentChanged) |
|
1644 { |
|
1645 return ETrue; |
|
1646 } |
|
1647 } |
|
1648 else |
|
1649 { |
|
1650 return EFalse; |
|
1651 } |
|
1652 return EFalse; |
|
1653 } |
|
1654 |
|
1655 TBool CControlCommand::NormalCommand() |
|
1656 { |
|
1657 TBool ret = ETrue; |
|
1658 TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId); |
|
1659 TMetadataTransferPDU pduId = RAvrcpIPC::GetPDUIdFromIPCOperationId(iOperationId); |
|
1660 |
|
1661 if((eventId == ERegisterNotificationAvailablePlayersChanged) || |
|
1662 (eventId == ERegisterNotificationAddressedPlayerChanged)) |
|
1663 { |
|
1664 ret = EFalse; |
|
1665 } |
|
1666 return ret; |
|
1667 } |
|
1668 /** |
|
1669 @return Ownership of a CControlCommand representing an interim response to this command |
|
1670 */ |
|
1671 CControlCommand* CControlCommand::InterimResponseL() |
|
1672 { |
|
1673 CAVCFrame* frame = CAVCFrame::NewL(iFrame->Data(), AVC::EResponse); |
|
1674 CleanupStack::PushL(frame); |
|
1675 frame->SetType(AVC::EInterim); |
|
1676 |
|
1677 CControlCommand* finalResponse = CControlCommand::NewL(frame, iRemConId, |
|
1678 iTransactionLabel, iRemoteAddr, iClientId, iPlayerInfoManager); |
|
1679 CleanupStack::Pop(frame); |
|
1680 |
|
1681 finalResponse->iInterfaceUid = iInterfaceUid; |
|
1682 finalResponse->iOperationId = iOperationId; |
|
1683 |
|
1684 return finalResponse; |
|
1685 } |
|
1686 |
|