|
1 // Copyright (c) 2008-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 // This file contains the events part of the PlayerInformation API. |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @publishedAll |
|
21 @released |
|
22 */ |
|
23 |
|
24 #include <bluetooth/logger.h> |
|
25 #include <remconinterfaceselector.h> |
|
26 #include <remconbeareravrcp.h> |
|
27 #include <playerinformationtarget.h> |
|
28 #include <playerinformationtargetobserver.h> |
|
29 |
|
30 #include "playerapplicationsetting.h" |
|
31 #include "eventsmask.h" |
|
32 #include "playereventsutils.h" |
|
33 #include "playerinformation.h" |
|
34 |
|
35 #ifdef __FLOG_ACTIVE |
|
36 _LIT8(KLogComponent, LOG_COMPONENT_AVRCP_PLAYER_INFO); |
|
37 #endif |
|
38 |
|
39 EXPORT_C void MPlayerEventsObserver::PlaybackStatusChanged(TPlaybackStatus aStatus) |
|
40 { |
|
41 DoPlaybackStatusChanged(aStatus); |
|
42 } |
|
43 |
|
44 EXPORT_C void MPlayerEventsObserver::TrackChanged(TUint64 aTrackId, TUint32 aLengthInMilliseconds) |
|
45 { |
|
46 DoTrackChanged(aTrackId, aLengthInMilliseconds); |
|
47 } |
|
48 |
|
49 EXPORT_C void MPlayerEventsObserver::TrackReachedEnd() |
|
50 { |
|
51 DoTrackReachedEnd(); |
|
52 } |
|
53 |
|
54 EXPORT_C void MPlayerEventsObserver::TrackReachedStart() |
|
55 { |
|
56 DoTrackReachedStart(); |
|
57 } |
|
58 |
|
59 EXPORT_C void MPlayerEventsObserver::SetPlaybackPosition(TUint32 aMilliseconds) |
|
60 { |
|
61 DoSetPlaybackPosition(aMilliseconds); |
|
62 } |
|
63 |
|
64 EXPORT_C void MPlayerEventsObserver::SetBatteryStatus(TTargetBatteryStatus aBatteryStatus) |
|
65 { |
|
66 DoSetBatteryStatus(aBatteryStatus); |
|
67 } |
|
68 |
|
69 void CPlayerInfoTarget::ProcessGetStatusAndBeginObserving( const TUint aOperationId, TRegisterNotificationEvent aEventId, const TDesC8& aData) |
|
70 { |
|
71 // check the event is in the supported list |
|
72 if (!iSupportedNotificationEventList->Find(aEventId)) |
|
73 { |
|
74 // Not supported so return error |
|
75 SendError(KErrAvrcpMetadataInvalidParameter, aOperationId, ERemConNotifyResponseInterim); |
|
76 return; |
|
77 } |
|
78 |
|
79 // if the event is EPlaybackPosChanged then the timeinterval is included in the RegisterNofication |
|
80 if (aEventId == ERegisterNotificationPlaybackPosChanged) |
|
81 { |
|
82 // decode the playback interval from aData |
|
83 TInt error = 0; |
|
84 RRemConPlayerInformation32BitResponse request; |
|
85 TRAP(error, request.ReadL(aData)); |
|
86 |
|
87 if (error != KErrNone) |
|
88 { |
|
89 // Not supported so return error |
|
90 SendError(KErrAvrcpMetadataParameterNotFound, aOperationId, ERemConNotifyResponseInterim); |
|
91 return; |
|
92 } |
|
93 |
|
94 // save the playback interval |
|
95 iPlayBackIntervalInMilliseconds = request.iValue * 1000; |
|
96 |
|
97 // and the current position |
|
98 iLastNotifiedPlaybackPositionInMilliseconds = iPlaybackPositionInMilliseconds; |
|
99 } |
|
100 |
|
101 // and request another notification (if there is not one already pending) |
|
102 // on the next state change |
|
103 if (KErrNotFound ==iPendingNotificationEventList.Find(aEventId)) |
|
104 { |
|
105 if (iPendingNotificationEventList.Append(aEventId) != KErrNone) |
|
106 { |
|
107 return SendError(KErrAvrcpMetadataInternalError, aOperationId); // Try to send internal error if OOM |
|
108 } |
|
109 } |
|
110 |
|
111 // send the current status |
|
112 SendNotificationResponse(aEventId, ERemConNotifyResponseInterim ); |
|
113 } |
|
114 |
|
115 void CPlayerInfoTarget::ProcessGetStatus( const TUint aOperationId, TRegisterNotificationEvent aEventId) |
|
116 { |
|
117 // send the current value |
|
118 if (iSupportedNotificationEventList->Find(aEventId)) |
|
119 { |
|
120 SendNotificationResponse(aEventId, ERemConNotifyResponseChanged ); |
|
121 } |
|
122 else |
|
123 { |
|
124 // Not found so return error |
|
125 SendError(KErrAvrcpMetadataInvalidParameter, aOperationId, ERemConNotifyResponseChanged); |
|
126 } |
|
127 } |
|
128 |
|
129 /* ProcessGetPlayStatus This returns the current values of SongLength, |
|
130 SongPosition and PlayStatus. |
|
131 Note if SongLength and SongPosition are not supported KPlaybackPositionUnknown is returned |
|
132 */ |
|
133 void CPlayerInfoTarget::ProcessGetPlayStatus() |
|
134 { |
|
135 LOG_FUNC |
|
136 |
|
137 TInt error =0; |
|
138 |
|
139 // format the response in a RRemConPlayerInformationGetPlayStatusResponse |
|
140 RRemConPlayerInformationGetPlayStatusResponse response; |
|
141 response.iTrackLength = iLengthInMilliseconds; |
|
142 response.iPlayPos = iPlaybackPositionInMilliseconds; |
|
143 response.iStatus = iPlayBackStatus; |
|
144 |
|
145 TRAP(error, response.WriteL(iOutBuf)); |
|
146 if (error == KErrNone) |
|
147 { |
|
148 // send the response back to the CT |
|
149 error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), |
|
150 EGetPlayStatus, ERemConResponse, iOutBuf ); |
|
151 } |
|
152 } |
|
153 |
|
154 /* ProcessGetPlayStatusUpdate returns the current play status if it has changed |
|
155 * relative to the provided play status, otherwise the request is queued until |
|
156 * the play status changes. |
|
157 */ |
|
158 void CPlayerInfoTarget::ProcessGetPlayStatusUpdate(const TDesC8& aData) |
|
159 { |
|
160 LOG_FUNC |
|
161 |
|
162 // Bearer should never send us more than one of these in parallel |
|
163 __ASSERT_DEBUG(!iPlaybackStatusUpdatePending, PlayerEventsUtils::Panic(ETwoGetPlayStatusUpdatesQueued)); |
|
164 |
|
165 TInt error =0; |
|
166 RRemConPlayerInformationGetPlayStatusUpdateRequest request; |
|
167 TRAP(error, request.ReadL(aData)); |
|
168 __ASSERT_DEBUG(error == KErrNone, PlayerEventsUtils::Panic(EBadlyFormattedInternalData)); |
|
169 |
|
170 if(request.iStatus != iPlayBackStatus) |
|
171 { |
|
172 // format the response in a RRemConPlayerInformationGetPlayStatusResponse |
|
173 RRemConPlayerInformationGetPlayStatusUpdateResponse response; |
|
174 response.iStatus = iPlayBackStatus; |
|
175 |
|
176 TRAP(error, response.WriteL(iOutBuf)); |
|
177 if (error == KErrNone) |
|
178 { |
|
179 // send the response back to the CT |
|
180 error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), |
|
181 EGetPlayStatusUpdate, ERemConResponse, iOutBuf ); |
|
182 if(error != KErrNone) |
|
183 { |
|
184 // We will try and send the response again next time we get an update |
|
185 iPlaybackStatusUpdatePending = ETrue; |
|
186 } |
|
187 } |
|
188 } |
|
189 else |
|
190 { |
|
191 iPlaybackStatusUpdatePending = ETrue; |
|
192 } |
|
193 } |
|
194 |
|
195 // Send a Notification message for aEventID |
|
196 void CPlayerInfoTarget::SendNotificationResponse( TRegisterNotificationEvent aEventId, TRemConMessageSubType aMsgSubType ) |
|
197 { |
|
198 LOG_FUNC |
|
199 |
|
200 TInt error = 0; |
|
201 iOutBuf.Zero(); |
|
202 |
|
203 if (!iSupportedNotificationEventList->Find(aEventId)) |
|
204 { |
|
205 return SendError(KErrAvrcpMetadataInvalidParameter, |
|
206 RAvrcpIPC::SetIPCOperationIdFromEventId(aEventId), aMsgSubType); |
|
207 } |
|
208 |
|
209 switch (aEventId) |
|
210 { |
|
211 case ERegisterNotificationTrackReachedEnd: |
|
212 case ERegisterNotificationTrackReachedStart: |
|
213 { |
|
214 // no extra data for reached start or end |
|
215 RAvrcpIPCError response; |
|
216 response.iError = KErrNone; |
|
217 TRAP(error, response.WriteL(iOutBuf)); |
|
218 break; |
|
219 } |
|
220 |
|
221 case ERegisterNotificationPlaybackStatusChanged: |
|
222 { |
|
223 // 8bit response -- current playback status |
|
224 RRemConPlayerInformation8BitResponse response; |
|
225 response.iValue = iPlayBackStatus; |
|
226 TRAP(error, response.WriteL(iOutBuf)); |
|
227 break; |
|
228 } |
|
229 |
|
230 case ERegisterNotificationBatteryStatusChanged: |
|
231 { |
|
232 // 8bit response -- current battery status |
|
233 RRemConPlayerInformation8BitResponse response; |
|
234 response.iValue = iBatteryStatus; |
|
235 TRAP(error, response.WriteL(iOutBuf)); |
|
236 break; |
|
237 } |
|
238 |
|
239 case ERegisterNotificationPlaybackPosChanged: |
|
240 { |
|
241 // 32bit response -- current playback position in millisecond |
|
242 RRemConPlayerInformation32BitResponse response; |
|
243 response.iValue = iPlaybackPositionInMilliseconds; |
|
244 TRAP(error, response.WriteL(iOutBuf)); |
|
245 break; |
|
246 } |
|
247 |
|
248 case ERegisterNotificationTrackChanged: |
|
249 { |
|
250 // 64bit response -- index of the current track |
|
251 RRemConPlayerInformation64BitResponse response; |
|
252 response.iValue = iTrackId; |
|
253 TRAP(error, response.WriteL(iOutBuf)); |
|
254 break; |
|
255 } |
|
256 |
|
257 case ERegisterNotificationPlayerApplicationSettingChanged: |
|
258 { |
|
259 // Send a list of the settings that have changed followed by their value |
|
260 // starting with the number of attributes to be sent |
|
261 RRemConPlayerAttributeIdsAndValues response; |
|
262 response.iNumberAttributes = 0; |
|
263 |
|
264 // for every entry in the list |
|
265 THashMapIter<TInt, CPlayerApplicationSettings*> iter(iPlayerApplicationSettings); |
|
266 CPlayerApplicationSettings* const* setting = iter.NextValue(); |
|
267 while ( setting != NULL ) |
|
268 { |
|
269 TUint8 value = (*setting)->GetCurrentValue(); |
|
270 TInt ret1 = response.iAttributeValue.Append(value); |
|
271 TInt ret2 = response.iAttributeId.Append((*setting)->GetAttributeID()); |
|
272 if (ret1 != KErrNone || ret2 != KErrNone) |
|
273 { |
|
274 response.Close(); |
|
275 return SendError(KErrAvrcpMetadataInternalError, |
|
276 RAvrcpIPC::SetIPCOperationIdFromEventId(aEventId), |
|
277 aMsgSubType); // Try to send internal error if OOM |
|
278 } |
|
279 response.iNumberAttributes++; |
|
280 setting = iter.NextValue(); |
|
281 } |
|
282 |
|
283 TRAP(error, response.WriteL(iOutBuf)); |
|
284 response.Close(); |
|
285 break; |
|
286 } |
|
287 default: |
|
288 return; |
|
289 } |
|
290 |
|
291 if (error == KErrNone) |
|
292 { |
|
293 // send the response back to the CT |
|
294 TUint operationId = RAvrcpIPC::SetIPCOperationIdFromEventId(aEventId); |
|
295 error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), |
|
296 operationId, ERemConResponse, aMsgSubType, iOutBuf); |
|
297 } |
|
298 } |
|
299 |
|
300 // from MPlayerEventsObserver |
|
301 void CPlayerInfoTarget::DoPlaybackStatusChanged(TPlaybackStatus aStatus) |
|
302 { |
|
303 LOG_FUNC |
|
304 |
|
305 iPlayBackStatus = aStatus; |
|
306 |
|
307 // if the playback status is in the current event list |
|
308 TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackStatusChanged ); |
|
309 if (pos != KErrNotFound) |
|
310 { |
|
311 iPendingNotificationEventList.Remove( pos ); |
|
312 SendNotificationResponse( ERegisterNotificationPlaybackStatusChanged, ERemConNotifyResponseChanged); |
|
313 } |
|
314 |
|
315 pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged ); |
|
316 if (pos != KErrNotFound) |
|
317 { |
|
318 iPendingNotificationEventList.Remove( pos ); |
|
319 SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged); |
|
320 } |
|
321 |
|
322 if(iPlaybackStatusUpdatePending) |
|
323 { |
|
324 // format the response in a RRemConPlayerInformationGetPlayStatusResponse |
|
325 RRemConPlayerInformationGetPlayStatusUpdateResponse response; |
|
326 response.iStatus = iPlayBackStatus; |
|
327 |
|
328 TRAPD(error, response.WriteL(iOutBuf)); |
|
329 if (error == KErrNone) |
|
330 { |
|
331 // send the response back to the CT |
|
332 error = InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), |
|
333 EGetPlayStatusUpdate, ERemConResponse, iOutBuf ); |
|
334 if(error == KErrNone) |
|
335 { |
|
336 iPlaybackStatusUpdatePending = EFalse; |
|
337 } |
|
338 // if we did error we will try and respond again next time the client's play status |
|
339 // changes |
|
340 } |
|
341 } |
|
342 } |
|
343 |
|
344 void CPlayerInfoTarget::DoTrackChanged(TUint64 aTrackId, TUint32 aLengthInMilliseconds) |
|
345 { |
|
346 LOG_FUNC |
|
347 |
|
348 iTrackId = aTrackId; |
|
349 iLengthInMilliseconds = aLengthInMilliseconds; |
|
350 |
|
351 // if the playback status is in the current event list |
|
352 TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationTrackChanged ); |
|
353 if (pos != KErrNotFound) |
|
354 { |
|
355 iPendingNotificationEventList.Remove( pos ); |
|
356 SendNotificationResponse(ERegisterNotificationTrackChanged, ERemConNotifyResponseChanged); |
|
357 } |
|
358 |
|
359 pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged ); |
|
360 if (pos != KErrNotFound) |
|
361 { |
|
362 iPendingNotificationEventList.Remove( pos ); |
|
363 iPlaybackPositionInMilliseconds = 0; //set 0 to current position for new track |
|
364 SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged); |
|
365 } |
|
366 } |
|
367 |
|
368 void CPlayerInfoTarget::DoTrackReachedEnd() |
|
369 { |
|
370 LOG_FUNC |
|
371 |
|
372 iTrackPosition = EEnd; |
|
373 |
|
374 // if the ETrackReachedEnd status is in the current event list |
|
375 TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationTrackReachedEnd ); |
|
376 if (pos != KErrNotFound) |
|
377 { |
|
378 iPendingNotificationEventList.Remove( pos ); |
|
379 SendNotificationResponse(ERegisterNotificationTrackReachedEnd, ERemConNotifyResponseChanged); |
|
380 } |
|
381 |
|
382 pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged ); |
|
383 if (pos != KErrNotFound) |
|
384 { |
|
385 iPendingNotificationEventList.Remove( pos ); |
|
386 iPlaybackPositionInMilliseconds = iLengthInMilliseconds; |
|
387 SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged); |
|
388 } |
|
389 } |
|
390 |
|
391 void CPlayerInfoTarget::DoTrackReachedStart() |
|
392 { |
|
393 LOG_FUNC |
|
394 |
|
395 iTrackPosition = EStart; |
|
396 |
|
397 // if the ETrackReachedStart status is in the current event list |
|
398 TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationTrackReachedStart ); |
|
399 if (pos != KErrNotFound) |
|
400 { |
|
401 iPendingNotificationEventList.Remove( pos ); |
|
402 SendNotificationResponse(ERegisterNotificationTrackReachedStart, ERemConNotifyResponseChanged); |
|
403 } |
|
404 |
|
405 pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged ); |
|
406 if (pos != KErrNotFound) |
|
407 { |
|
408 iPendingNotificationEventList.Remove( pos ); |
|
409 iPlaybackPositionInMilliseconds = 0; |
|
410 SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged); |
|
411 } |
|
412 } |
|
413 |
|
414 void CPlayerInfoTarget::DoSetPlaybackPosition(TUint32 aMilliseconds) |
|
415 { |
|
416 LOG_FUNC |
|
417 |
|
418 iPlaybackPositionInMilliseconds = aMilliseconds; |
|
419 |
|
420 // if the playback position is in the current Notification event list |
|
421 TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationPlaybackPosChanged ); |
|
422 if (pos != KErrNotFound) |
|
423 { |
|
424 // a notification has been requested, now check if it is due |
|
425 |
|
426 TUint32 difference = (iPlaybackPositionInMilliseconds > iLastNotifiedPlaybackPositionInMilliseconds) ? |
|
427 iPlaybackPositionInMilliseconds - iLastNotifiedPlaybackPositionInMilliseconds: |
|
428 iLastNotifiedPlaybackPositionInMilliseconds - iPlaybackPositionInMilliseconds; |
|
429 |
|
430 if (difference >= iPlayBackIntervalInMilliseconds) |
|
431 { |
|
432 // Due now so send |
|
433 iPendingNotificationEventList.Remove( pos ); |
|
434 SendNotificationResponse(ERegisterNotificationPlaybackPosChanged, ERemConNotifyResponseChanged); |
|
435 } |
|
436 } |
|
437 } |
|
438 |
|
439 void CPlayerInfoTarget::DoSetBatteryStatus(TTargetBatteryStatus aBatteryStatus) |
|
440 { |
|
441 LOG_FUNC |
|
442 |
|
443 TBool validStatus = ETrue; |
|
444 if (aBatteryStatus < MPlayerEventsObserver::ENormal || |
|
445 aBatteryStatus > MPlayerEventsObserver::EFullCharge) |
|
446 { |
|
447 LOG1(_L("Invalid battery status: %d"),aBatteryStatus); |
|
448 validStatus = EFalse; |
|
449 } |
|
450 else |
|
451 { |
|
452 iBatteryStatus = aBatteryStatus; |
|
453 } |
|
454 |
|
455 // if the battery status is in the current event list |
|
456 TInt pos = iPendingNotificationEventList.Find( ERegisterNotificationBatteryStatusChanged ); |
|
457 if (pos != KErrNotFound) |
|
458 { |
|
459 iPendingNotificationEventList.Remove( pos ); |
|
460 if (validStatus) |
|
461 { |
|
462 SendNotificationResponse(ERegisterNotificationBatteryStatusChanged, ERemConNotifyResponseChanged); |
|
463 } |
|
464 } |
|
465 } |
|
466 |
|
467 void CPlayerInfoTarget::SendError(TInt aError, TInt aOperationId, TRemConMessageSubType aSubType) |
|
468 { |
|
469 TInt error = 0; |
|
470 RAvrcpIPCError response; |
|
471 response.iError = aError; |
|
472 TRAP(error, response.WriteL(iOutBuf)); // Don't send error if OOM |
|
473 if (error == KErrNone) |
|
474 InterfaceSelector().SendUnreliable(TUid::Uid(KRemConPlayerInformationUid), |
|
475 aOperationId, ERemConResponse, aSubType, iOutBuf); |
|
476 } |
|
477 |