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 |
|
24 #include <bluetoothav.h> |
|
25 |
|
26 #include "avrcpcommand.h" |
|
27 #include "avrcplog.h" |
|
28 #include "avrcprouter.h" |
|
29 #include "avrcputils.h" |
|
30 #include "commandhandlerinterface.h" |
|
31 |
|
32 using namespace SymbianAvctp; |
|
33 |
|
34 /** Constructor. |
|
35 |
|
36 @param aRemotes The list of remote devices known to AVRCP. |
|
37 @param aBearer The bearer. |
|
38 @return A partially constructed CRcpRouter. |
|
39 */ |
|
40 CRcpRouter::CRcpRouter(MAvrcpBearer& aBearer) |
|
41 : iChannel(NULL) |
|
42 , iBearer(aBearer) |
|
43 , iSendQueue(_FOFF(CAvrcpCommand, iSendLink)) |
|
44 , iState(EAvrcpRouterCanSend) |
|
45 { |
|
46 LOG_FUNC |
|
47 } |
|
48 |
|
49 /** Destructor. |
|
50 */ |
|
51 CRcpRouter::~CRcpRouter() |
|
52 { |
|
53 LOG_FUNC |
|
54 // The lifetime of the Router is the same as that of the bearer plugin. |
|
55 // This means that there is no point worrying about the stuff on our |
|
56 // send queue as we won't be around to pass the results up to RemCon. |
|
57 while (!iSendQueue.IsEmpty()) |
|
58 { |
|
59 CAvrcpCommand *command = iSendQueue.First(); |
|
60 command->iSendLink.Deque(); |
|
61 command->DecrementUsers(); |
|
62 } |
|
63 } |
|
64 |
|
65 //------------------------------------------------------------------ |
|
66 // Data functions called from command handlers |
|
67 //------------------------------------------------------------------ |
|
68 |
|
69 /** Adds command to send queue. |
|
70 |
|
71 This message will be sent as soon as the iAvcp becomes |
|
72 free for sending, unless the command is removed before |
|
73 then. |
|
74 |
|
75 @param aCommand The command to send. |
|
76 @see CRcpRouter::RemoveFromSendQueue |
|
77 */ |
|
78 void CRcpRouter::AddToSendQueue(CAvrcpCommand& aCommand) |
|
79 { |
|
80 LOG_FUNC |
|
81 |
|
82 __ASSERT_ALWAYS(!aCommand.iSendLink.IsQueued(), AVRCP_PANIC(ECommandAlreadyQueuedForSending)); |
|
83 |
|
84 iSendQueue.AddLast(aCommand); |
|
85 aCommand.IncrementUsers(); |
|
86 |
|
87 if(iState == EAvrcpRouterCanSend) |
|
88 { |
|
89 Send(); |
|
90 } |
|
91 } |
|
92 |
|
93 /** Remove command from send queue. |
|
94 |
|
95 @param aCommand The command that is not to be sent. |
|
96 */ |
|
97 void CRcpRouter::RemoveFromSendQueue(CAvrcpCommand& aCommand) |
|
98 { |
|
99 LOG_FUNC |
|
100 |
|
101 if(iSendQueue.IsFirst(&aCommand)) |
|
102 { |
|
103 // If this is at the front of the queue it's currently being |
|
104 // sent. Cancel that and start off the next thing. |
|
105 iChannel->MacCancelSend(); |
|
106 aCommand.iSendLink.Deque(); |
|
107 iState = EAvrcpRouterCanSend; |
|
108 if(!iSendQueue.IsEmpty()) |
|
109 { |
|
110 Send(); |
|
111 } |
|
112 } |
|
113 else |
|
114 { |
|
115 // Still waiting to be sent so we can just sneak it out of |
|
116 // the queue. |
|
117 aCommand.iSendLink.Deque(); |
|
118 } |
|
119 } |
|
120 |
|
121 //------------------------------------------------------------------ |
|
122 // Control functions called from bearer |
|
123 //------------------------------------------------------------------ |
|
124 |
|
125 /** Try to bring up an explicit connection to a remote. |
|
126 |
|
127 @param aAddr The address of the remote. |
|
128 @return System wide error. KErrNone if this request will be |
|
129 attempted, and generate a ConnectConfirm. |
|
130 */ |
|
131 TInt CRcpRouter::ConnectRequest(const TBTDevAddr& aAddr) |
|
132 { |
|
133 LOG_FUNC |
|
134 return iChannel->MacAttachRequest(aAddr); |
|
135 } |
|
136 |
|
137 /** Try to bring down an explicit connection to a remote. |
|
138 |
|
139 @param aAddr The address of the remote. |
|
140 @return System wide error. KErrNone if the disconnect will be |
|
141 attempted, and generate a DisconnectConfirm. |
|
142 */ |
|
143 TInt CRcpRouter::DisconnectRequest(const TBTDevAddr& aAddr) |
|
144 { |
|
145 LOG_FUNC |
|
146 return iChannel->MacDetachRequest(aAddr); |
|
147 } |
|
148 |
|
149 //------------------------------------------------------------------ |
|
150 // MAvctpEventNotify functions called from RAvctp |
|
151 //------------------------------------------------------------------ |
|
152 |
|
153 /** AVCTP Connection Indicate. |
|
154 |
|
155 This is called when a remote device has connected |
|
156 to us. NB we don't return the configuration status as |
|
157 in Appendix A - AVCTP Upper Interface of [R2]. If aAccept |
|
158 is not changed the connection will be refused however |
|
159 this may not result in the actual disconnection of the |
|
160 device if another RAvctp client did accept the connection. |
|
161 |
|
162 @param aBTDevice the address of the device connected to |
|
163 @param aAccept this parameter is provided so that the client |
|
164 of RAvctp can indicate whether they want to accept the |
|
165 connection. The meaning of a refusal is that you don't |
|
166 care whether or not the connection is there or not. |
|
167 @see RAvctp |
|
168 */ |
|
169 void CRcpRouter::MaenAttachIndicate(const TBTDevAddr& aBTDevice, TInt aMtu, TBool& aAccept) |
|
170 { |
|
171 LOG_FUNC |
|
172 aAccept = ETrue; |
|
173 |
|
174 // if we have already received data from this device we will have |
|
175 // informed RemCon about it already, so don't pass up the connection |
|
176 // now |
|
177 if(!iBearer.IncomingHandler(aBTDevice)) |
|
178 { |
|
179 iBearer.ConnectIndicate(aBTDevice); |
|
180 } |
|
181 |
|
182 MIncomingCommandHandler* handler = iBearer.IncomingHandler(aBTDevice); |
|
183 if(handler) |
|
184 { |
|
185 handler->MaxPacketSize(aMtu); |
|
186 aAccept = ETrue; |
|
187 } |
|
188 else |
|
189 { |
|
190 aAccept = EFalse; |
|
191 } |
|
192 } |
|
193 |
|
194 /** AVCTP Connection Confirm. |
|
195 |
|
196 This is a response to RAvctp::ConnectRequest and passes on the |
|
197 result of the Connection attempt. NB we don't return the |
|
198 configuration status as in Appendix A - AVCTP Upper |
|
199 Interface of [R2]. If the aConnectResult is KErrNone |
|
200 then iAvctp is now connected. |
|
201 |
|
202 @param aBTDevice the address of the device connected to |
|
203 @param aConnectResult connection result - one of the |
|
204 system-wide error codes. |
|
205 @see RAvctp |
|
206 */ |
|
207 void CRcpRouter::MaenAttachConfirm(const TBTDevAddr& aBTDevice, TInt aMtu, TInt aConnectResult) |
|
208 { |
|
209 LOG_FUNC |
|
210 iBearer.ConnectConfirm(aBTDevice, aConnectResult); |
|
211 |
|
212 MIncomingCommandHandler* handler = iBearer.IncomingHandler(aBTDevice); |
|
213 if(handler) |
|
214 { |
|
215 handler->MaxPacketSize(aMtu); |
|
216 } |
|
217 } |
|
218 |
|
219 /** AVCTP Disconnection Indication. |
|
220 |
|
221 Indicates that a remote device has disconnected from us. |
|
222 It is only called if the device had been explicitly Connected to. |
|
223 |
|
224 @param aBTDevice the address of the disconnecting device |
|
225 @see RAvctp |
|
226 */ |
|
227 void CRcpRouter::MaenDetachIndicate(const TBTDevAddr& aBTDevice) |
|
228 { |
|
229 LOG_FUNC |
|
230 iBearer.DisconnectIndicate(aBTDevice); |
|
231 } |
|
232 |
|
233 /** AVCTP Disconnection Confirm. |
|
234 |
|
235 @param aBTDevice the address of the disconnected device |
|
236 @param aDisconnectResult will be one of the system-wide |
|
237 error codes. If KErrTimedOut is |
|
238 returned then the RAvctp will be |
|
239 disconnected. |
|
240 @see RAvctp |
|
241 */ |
|
242 void CRcpRouter::MaenDetachConfirm(const TBTDevAddr& aBTDevice, TInt aDisconnectResult) |
|
243 { |
|
244 LOG_FUNC |
|
245 iBearer.DisconnectConfirm(aBTDevice, aDisconnectResult); |
|
246 } |
|
247 |
|
248 /** AVCTP Message received indication. |
|
249 |
|
250 This method is called when a message has been received from |
|
251 the given device on the RAvctp's PID. |
|
252 |
|
253 Note that because AVCTP is a connectionless protocol, it is |
|
254 perfectly possible to get a MaenMessageReceivedIndicate event |
|
255 from a device that you have not either explicitly connected to. |
|
256 For instance even if you don't accept a MaenConnectIndicate |
|
257 you may still receive messages from that remote device. |
|
258 |
|
259 @param aBTDevice address of the device sending us an AVCTP message |
|
260 @param aTransactionLabel message transaction label |
|
261 @param aType type of message |
|
262 @param aIpidBitSet this will be set to true only if a message has been received indicating |
|
263 that the profile corresponding to the originally sent message is not valid. |
|
264 If RAvctp was used to send the message then this response will have come from |
|
265 the remote device aBTDevice. |
|
266 @param aMessageInformation contains only the AVCTP Command / Response Message Information and not the whole packet. |
|
267 Ownership transferred to client. |
|
268 @see RAvctp |
|
269 */ |
|
270 void CRcpRouter::MaenMessageReceivedIndicate(const TBTDevAddr& aBTDevice, |
|
271 SymbianAvctp::TTransactionLabel aTransactionLabel, |
|
272 SymbianAvctp::TMessageType aType, |
|
273 TBool aIpidBitSet, |
|
274 const TDesC8& aMessageInformation) |
|
275 { |
|
276 LOG_FUNC |
|
277 AVRCPLOG(aMessageInformation) |
|
278 |
|
279 // Find the right handler |
|
280 if(aType == ECommand) |
|
281 { |
|
282 MIncomingCommandHandler* handler = iBearer.IncomingHandler(aBTDevice); |
|
283 |
|
284 if(!handler) |
|
285 { |
|
286 iBearer.ConnectIndicate(aBTDevice); |
|
287 |
|
288 handler = iBearer.IncomingHandler(aBTDevice); |
|
289 } |
|
290 |
|
291 if(handler) |
|
292 { |
|
293 // If this leaves the handler is rejecting handling this command, just |
|
294 // ignore it. |
|
295 TRAP_IGNORE(handler->ReceiveCommandL(aMessageInformation, aTransactionLabel, aBTDevice)); |
|
296 } |
|
297 } |
|
298 else |
|
299 { |
|
300 MOutgoingCommandHandler* handler = iBearer.OutgoingHandler(aBTDevice); |
|
301 if(handler) |
|
302 { |
|
303 handler->ReceiveResponse(aMessageInformation, aTransactionLabel, aIpidBitSet); |
|
304 } |
|
305 } |
|
306 } |
|
307 |
|
308 /** AVCTP Message send complete. |
|
309 |
|
310 This method is called when a RAvctp has attempted to send |
|
311 the message defined by aTransactionLabel and aBTDevice. |
|
312 @param aTransactionLabel The transaction label of the message |
|
313 that has been sent |
|
314 @param aBTDevice the device to which the send has completed |
|
315 @param aSendResult KErrNone if the send was successful or one |
|
316 of the system-wide error codes |
|
317 @see RAvctp |
|
318 */ |
|
319 void CRcpRouter::MaenMessageSendComplete(const TBTDevAddr& aBTDevice, |
|
320 SymbianAvctp::TTransactionLabel aTransactionLabel, |
|
321 TInt aSendResult) |
|
322 { |
|
323 LOG_FUNC |
|
324 __ASSERT_ALWAYS(!iSendQueue.IsEmpty(), AvrcpUtils::Panic(EAvrcpNoOutstandingSend)); |
|
325 |
|
326 CAvrcpCommand* command = iSendQueue.First(); |
|
327 |
|
328 __ASSERT_ALWAYS(command->TransactionLabel() == aTransactionLabel, AvrcpUtils::Panic(EAvrcpUnknownAvctpTransId)); |
|
329 |
|
330 MAvrcpCommandHandler* handler = NULL; |
|
331 if(command->MessageType() == ECommand) |
|
332 { |
|
333 handler = iBearer.OutgoingHandler(aBTDevice); |
|
334 } |
|
335 else |
|
336 { |
|
337 handler = iBearer.IncomingHandler(aBTDevice); |
|
338 } |
|
339 |
|
340 if(handler) |
|
341 { |
|
342 handler->MessageSent(*command, aSendResult); |
|
343 } |
|
344 |
|
345 // Deque before calling Decrement because Decrement handling may involve |
|
346 // deleting command |
|
347 command->iSendLink.Deque(); |
|
348 command->DecrementUsers(); |
|
349 |
|
350 // Now able to do another send. Toggle our state and check if there |
|
351 // are any commands waiting. |
|
352 iState = EAvrcpRouterCanSend; |
|
353 if(!iSendQueue.IsEmpty()) |
|
354 { |
|
355 Send(); |
|
356 } |
|
357 } |
|
358 |
|
359 /** AVCTP Close Complete. |
|
360 |
|
361 This is the response to the CloseGracefully() that has been |
|
362 called on a RAvctp object. It is the last event that will be |
|
363 called until the RAvctp object is Open()'d again. |
|
364 @see RAvctp |
|
365 */ |
|
366 void CRcpRouter::MaenCloseComplete() |
|
367 { |
|
368 LOG_FUNC |
|
369 } |
|
370 |
|
371 /** AVCTP error notification. |
|
372 |
|
373 Note an errored device does not indicate that the device has |
|
374 been disconnected. If it has then a MaenDisconnectIndicate |
|
375 event will be used to indicate this. |
|
376 |
|
377 @param aBTDevice the remote device associated with the error or TBTDevAddr(0) for a general error |
|
378 @param aError system wide error |
|
379 @see RAvctp |
|
380 */ |
|
381 void CRcpRouter::MaenErrorNotify(const TBTDevAddr& /*aBTDevice*/, TInt /*aError*/) |
|
382 { |
|
383 LOG_FUNC |
|
384 } |
|
385 |
|
386 /** |
|
387 Returns a null aObject if the extension is not implemented, |
|
388 or a pointer to another interface if it is. |
|
389 |
|
390 @param aInterface UID of the interface to return |
|
391 @param aObject system wide error |
|
392 @see RAvctp |
|
393 */ |
|
394 void CRcpRouter::MaenExtensionInterfaceL(TUid /*aInterface*/, void*& aObject) |
|
395 { |
|
396 LOG_FUNC |
|
397 aObject = NULL; |
|
398 } |
|
399 |
|
400 //------------------------------------------------------------------ |
|
401 // Utility functions |
|
402 //------------------------------------------------------------------ |
|
403 |
|
404 /** Issue a send to AVCTP. |
|
405 |
|
406 This sends the first message on the command queue. |
|
407 */ |
|
408 void CRcpRouter::Send() |
|
409 { |
|
410 LOG_FUNC |
|
411 __ASSERT_ALWAYS(!iSendQueue.IsEmpty(), AvrcpUtils::Panic(EAvrcpNoOutstandingSend)); |
|
412 |
|
413 CAvrcpCommand* command = iSendQueue.First(); |
|
414 |
|
415 #ifdef _DEBUG |
|
416 TInt err = |
|
417 #endif // _DEBUG |
|
418 iChannel->MacSendMessage(command->RemoteAddress(), |
|
419 command->TransactionLabel(), |
|
420 command->MessageType(), |
|
421 command->Data()); |
|
422 |
|
423 __ASSERT_DEBUG(err == KErrNone, AvrcpUtils::Panic(EAvrcpSendingMessageFailed)); |
|
424 |
|
425 iState = EAvrcpRouterSending; |
|
426 } |
|
427 |
|
428 /** Factory funtion. |
|
429 |
|
430 @param aAvctp An open RAvctp instance. |
|
431 @param aBearer The bearer. |
|
432 @return A fully constructed CRcpRouter. |
|
433 @leave System wide error codes. |
|
434 */ |
|
435 CControlRouter* CControlRouter::NewL(RAvctp& aAvctp, MAvrcpBearer& aBearer) |
|
436 { |
|
437 LOG_STATIC_FUNC |
|
438 CControlRouter* router = new(ELeave) CControlRouter(aAvctp, aBearer); |
|
439 CleanupStack::PushL(router); |
|
440 router->ConstructL(); |
|
441 CleanupStack::Pop(router); |
|
442 return router; |
|
443 } |
|
444 |
|
445 CControlRouter::~CControlRouter() |
|
446 { |
|
447 LOG_FUNC |
|
448 iAvctp.Close(RAvctp::ENormal); |
|
449 } |
|
450 |
|
451 CControlRouter::CControlRouter(RAvctp& aAvctp, MAvrcpBearer& aBearer) |
|
452 : CRcpRouter(aBearer) |
|
453 , iAvctp(aAvctp) |
|
454 { |
|
455 LOG_FUNC |
|
456 } |
|
457 |
|
458 void CControlRouter::ConstructL() |
|
459 { |
|
460 LOG_FUNC |
|
461 LEAVEIFERRORL(iAvctp.Open(*this, KAvrcpPid, iChannel)); |
|
462 } |
|
463 |
|
464 /** Factory funtion. |
|
465 |
|
466 @param aAvctp An open RAvctp instance. |
|
467 @param aBearer The bearer. |
|
468 @return A fully constructed CRcpRouter. |
|
469 @leave System wide error codes. |
|
470 */ |
|
471 CBulkRouter* CBulkRouter::NewL(RAvctp& aAvctp, MAvrcpBearer& aBearer) |
|
472 { |
|
473 LOG_STATIC_FUNC |
|
474 CBulkRouter* router = new(ELeave) CBulkRouter(aAvctp, aBearer); |
|
475 CleanupStack::PushL(router); |
|
476 router->ConstructL(); |
|
477 CleanupStack::Pop(router); |
|
478 return router; |
|
479 } |
|
480 |
|
481 CBulkRouter::~CBulkRouter() |
|
482 { |
|
483 LOG_FUNC |
|
484 iAvctp.UninstallSecondaryChannel(); |
|
485 } |
|
486 |
|
487 CBulkRouter::CBulkRouter(RAvctp& aAvctp, MAvrcpBearer& aBearer) |
|
488 : CRcpRouter(aBearer) |
|
489 , iAvctp(aAvctp) |
|
490 { |
|
491 LOG_FUNC |
|
492 } |
|
493 |
|
494 void CBulkRouter::ConstructL() |
|
495 { |
|
496 LOG_FUNC |
|
497 LEAVEIFERRORL(iAvctp.InstallSecondaryChannel(*this, iChannel)); |
|
498 } |
|
499 |
|