|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: This class implements legacy volume control of AVRCP Controller. |
|
15 * |
|
16 * |
|
17 */ |
|
18 |
|
19 // INCLUDE FILES |
|
20 #include <remconbeareravrcp.h> // KRemConBearerAvrcpImplementationUid = 0x1020685f |
|
21 #include <MediaStreamPropertiesPSKeys.h> |
|
22 #include <remconinterfaceselector.h> |
|
23 #include <remconcoreapicontroller.h> |
|
24 #include <remconaddress.h> |
|
25 #include <e32math.h> |
|
26 |
|
27 #include "btrccLegacyVolumeLevelController.h" |
|
28 #include "debug.h" |
|
29 |
|
30 const TInt KVolumeNotSynchronized = -1; |
|
31 const TInt KLegacyVolumeLevelSetServiceId = 0x03; |
|
32 |
|
33 const TInt KVolumeSyncRecheckTimer = 500000; // 0.5 second |
|
34 const TInt KVolumeCommandInterval = 50000; // 0.05 second |
|
35 |
|
36 const TInt KVolumeScaleMax = 15; |
|
37 |
|
38 // MODULE DATA STRUCTURES |
|
39 |
|
40 // ================= MEMBER FUNCTIONS ======================= |
|
41 |
|
42 // ----------------------------------------------------------------------------- |
|
43 // CBTRCCLegacyVolumeLevelController::NewL |
|
44 // Two-phased constructor. |
|
45 // ----------------------------------------------------------------------------- |
|
46 // |
|
47 CBTRCCLegacyVolumeLevelController* CBTRCCLegacyVolumeLevelController::NewL(CRemConInterfaceSelector& aInterfaceSelector, MBTRCCVolumeControllerObserver& aObserver) |
|
48 { |
|
49 CBTRCCLegacyVolumeLevelController* self = new (ELeave) CBTRCCLegacyVolumeLevelController(aObserver); |
|
50 CleanupStack::PushL(self); |
|
51 self->ConstructL(aInterfaceSelector); |
|
52 CleanupStack::Pop(self); |
|
53 return self; |
|
54 } |
|
55 |
|
56 // ----------------------------------------------------------------------------- |
|
57 // CBTRCCLegacyVolumeLevelController::CBTRCCVolumeLevelController |
|
58 // C++ constructor. |
|
59 // ----------------------------------------------------------------------------- |
|
60 // |
|
61 CBTRCCLegacyVolumeLevelController::CBTRCCLegacyVolumeLevelController(MBTRCCVolumeControllerObserver& aObserver) |
|
62 : CBTRCCVolumeLevelControllerBase(aObserver), iState(EStateWaitingForVolumeLevelChanges), iPhoneVolume(KVolumeNotSynchronized), |
|
63 iCurrentPhoneVolume(KVolumeNotSynchronized), iCurrentRemoteVolume(KVolumeNotSynchronized) |
|
64 { |
|
65 } |
|
66 |
|
67 // ----------------------------------------------------------------------------- |
|
68 // CBTRCCLegacyVolumeLevelController::ConstructL |
|
69 // Symbian 2nd phase constructor. |
|
70 // ----------------------------------------------------------------------------- |
|
71 // |
|
72 void CBTRCCLegacyVolumeLevelController::ConstructL(CRemConInterfaceSelector& aInterfaceSelector) |
|
73 { |
|
74 TRACE_FUNC |
|
75 CBTRCCVolumeLevelControllerBase::ConstructL(); |
|
76 iInterfaceSelector = &aInterfaceSelector; |
|
77 iRemConVolController = CRemConCoreApiController::NewL(aInterfaceSelector, *this); |
|
78 TRACE_INFO((_L("CRemConCoreApiController created"))) |
|
79 iBtrccLegacyVolumeActive = CBTRCCActive::NewL(*this, KLegacyVolumeLevelSetServiceId); |
|
80 TRACE_INFO((_L("CBTRCCActive created"))) |
|
81 iCtrlRTimer.CreateLocal(); |
|
82 TRACE_INFO((_L("RTimer created"))) |
|
83 iLocalMaxVolume = GetLocalMaxVolume(); |
|
84 } |
|
85 |
|
86 // ----------------------------------------------------------------------------- |
|
87 // Destructor. |
|
88 // ----------------------------------------------------------------------------- |
|
89 // |
|
90 CBTRCCLegacyVolumeLevelController::~CBTRCCLegacyVolumeLevelController() |
|
91 { |
|
92 TRACE_FUNC |
|
93 delete iBtrccLegacyVolumeActive; |
|
94 iCtrlRTimer.Close(); |
|
95 } |
|
96 |
|
97 // ----------------------------------------------------------------------------- |
|
98 // CBTRCCLegacyVolumeLevelController::DoStart |
|
99 // ----------------------------------------------------------------------------- |
|
100 // |
|
101 void CBTRCCLegacyVolumeLevelController::DoStart(TInt aInitialVolume) |
|
102 { |
|
103 TRACE_FUNC |
|
104 AdjustRemoteVolume(aInitialVolume); |
|
105 } |
|
106 |
|
107 // ----------------------------------------------------------------------------- |
|
108 // CBTRCCLegacyVolumeLevelController::DoStop |
|
109 // ----------------------------------------------------------------------------- |
|
110 // |
|
111 void CBTRCCLegacyVolumeLevelController::DoStop() |
|
112 { |
|
113 TRACE_FUNC |
|
114 iBtrccLegacyVolumeActive->Cancel(); |
|
115 iState = EStateWaitingForVolumeLevelChanges; |
|
116 } |
|
117 |
|
118 // ----------------------------------------------------------------------------- |
|
119 // CBTRCCLegacyVolumeLevelController::DoReset |
|
120 // ----------------------------------------------------------------------------- |
|
121 // |
|
122 void CBTRCCLegacyVolumeLevelController::DoReset() |
|
123 { |
|
124 TRACE_FUNC |
|
125 iBtrccLegacyVolumeActive->Cancel(); |
|
126 iCurrentRemoteVolume = KVolumeNotSynchronized; |
|
127 } |
|
128 |
|
129 // ----------------------------------------------------------------------------- |
|
130 // CBTRCCLegacyVolumeLevelController::AdjustRemoteVolume |
|
131 // ----------------------------------------------------------------------------- |
|
132 // |
|
133 void CBTRCCLegacyVolumeLevelController::AdjustRemoteVolume(TInt aVolume) |
|
134 { |
|
135 // A call to this is made when PS Key changes. |
|
136 TRACE_INFO((_L("CBTRCCLegacyVolumeLevelController::AdjustRemoteVolume, volume %d, state %d"), aVolume, iState)) |
|
137 iPhoneVolume = aVolume; |
|
138 |
|
139 if(iCurrentRemoteVolume == KVolumeNotSynchronized) |
|
140 { |
|
141 // We set current phone volume level as the reference synchronization point |
|
142 // if we haven't done it yet. Otherwise we synchronize remote to the current level. |
|
143 // Just synchronize volumes and return, there is nothing else to do at this point. |
|
144 iCurrentRemoteVolume = iPhoneVolume; |
|
145 return; |
|
146 } |
|
147 |
|
148 switch(iState) |
|
149 { |
|
150 case EStateWaitingForVolumeLevelChanges: |
|
151 // Just break here. |
|
152 break; |
|
153 case EStateDelay: |
|
154 // Sharp volume jump handling is ongoing. In this case we want to update |
|
155 // new volume level immediately. |
|
156 if( iBtrccLegacyVolumeActive->IsActive() ) |
|
157 { |
|
158 iBtrccLegacyVolumeActive->Cancel(); |
|
159 } |
|
160 break; |
|
161 default: |
|
162 // We are middle of timing or volume up/down processing. New value |
|
163 // is stored, just return here. New value is updated after previous |
|
164 // job is done. |
|
165 return; |
|
166 } |
|
167 |
|
168 DoRemoteControl(); |
|
169 } |
|
170 |
|
171 // ----------------------------------------------------------------------------- |
|
172 // CBTRCCLegacyVolumeLevelController::DoRemoteControl |
|
173 // ----------------------------------------------------------------------------- |
|
174 // |
|
175 void CBTRCCLegacyVolumeLevelController::DoRemoteControl() |
|
176 { |
|
177 TRACE_INFO((_L("target volume level %d"), iPhoneVolume)) |
|
178 TRACE_INFO((_L("phone current volume level %d"), iCurrentPhoneVolume)) |
|
179 TRACE_INFO((_L("remote current volume level %d"), iCurrentRemoteVolume)) |
|
180 |
|
181 TState preState = iState; |
|
182 iState = EStateWaitingForVolumeLevelChanges; |
|
183 |
|
184 if ( iPhoneVolume != iCurrentRemoteVolume ) |
|
185 { |
|
186 TInt prevPhoneVolume = iCurrentPhoneVolume; |
|
187 iCurrentPhoneVolume = iPhoneVolume; |
|
188 |
|
189 if ( iCurrentPhoneVolume == 0 && prevPhoneVolume > 1 ) |
|
190 { |
|
191 // A sharp volume jump, most probably caused by audio stream switching. |
|
192 // Delay the starting of audio adjustment for 0.5 seconds. |
|
193 iState = EStateDelay; |
|
194 } |
|
195 else if (iCurrentPhoneVolume > iCurrentRemoteVolume) |
|
196 { |
|
197 iState = preState == EStateVolumeUpTiming ? EStateVolumeUp : EStateVolumeUpTiming; |
|
198 } |
|
199 else if (iCurrentPhoneVolume < iCurrentRemoteVolume) |
|
200 { |
|
201 iState = preState == EStateVolumeDownTiming ? EStateVolumeDown : EStateVolumeDownTiming; |
|
202 } |
|
203 } |
|
204 |
|
205 switch (iState) |
|
206 { |
|
207 case EStateVolumeUpTiming: |
|
208 { |
|
209 TRACE_INFO(_L("Volume up timing")) |
|
210 StartTimer(KVolumeCommandInterval); |
|
211 break; |
|
212 } |
|
213 case EStateVolumeUp: |
|
214 { |
|
215 TRACE_INFO(_L("Volume up")) |
|
216 SendVolumeCommand(EStateVolumeUp); |
|
217 break; |
|
218 } |
|
219 case EStateVolumeDownTiming: |
|
220 { |
|
221 TRACE_INFO(_L("Volume down timing")) |
|
222 StartTimer(KVolumeCommandInterval); |
|
223 break; |
|
224 } |
|
225 case EStateVolumeDown: |
|
226 { |
|
227 TRACE_INFO(_L("Volume down")) |
|
228 SendVolumeCommand(EStateVolumeDown); |
|
229 break; |
|
230 } |
|
231 case EStateDelay: |
|
232 { |
|
233 TRACE_INFO(_L("Delay before updating volume")) |
|
234 StartTimer( KVolumeSyncRecheckTimer ); |
|
235 break; |
|
236 } |
|
237 case EStateWaitingForVolumeLevelChanges: |
|
238 { |
|
239 TRACE_INFO(_L("Waiting volume change")) |
|
240 break; |
|
241 } |
|
242 default: |
|
243 { |
|
244 // Not possible |
|
245 } |
|
246 } |
|
247 } |
|
248 |
|
249 // ----------------------------------------------------------------------------- |
|
250 // CBTRCCLegacyVolumeLevelController::GetPhoneVolume |
|
251 // ----------------------------------------------------------------------------- |
|
252 // |
|
253 TInt CBTRCCLegacyVolumeLevelController::GetPhoneVolume(TInt &aVol) |
|
254 { |
|
255 TRACE_FUNC |
|
256 TInt err = CBTRCCVolumeLevelControllerBase::GetPhoneVolume(aVol); |
|
257 |
|
258 // Converts volume level scale used in DevSound Audio (0 - 10000) into 0 - KVolumeScaleMax. |
|
259 if( aVol <= 0 ) |
|
260 { |
|
261 // 0 level and -1 (no stream) don't need adjustment. |
|
262 return err; |
|
263 } |
|
264 |
|
265 TReal tgt; |
|
266 TReal src(aVol); |
|
267 TReal maxScale(KVolumeScaleMax); |
|
268 TReal maxDevSound(iLocalMaxVolume); |
|
269 TReal scale = maxScale/maxDevSound; |
|
270 Math::Round( tgt, src*scale, 0); |
|
271 |
|
272 if( TInt(tgt) == 0 ) |
|
273 { |
|
274 // Only aVol value 0 is real zero (muted). All other scaled zero |
|
275 // values have to be upgraded to level 1. |
|
276 tgt = 1; |
|
277 } |
|
278 TRACE_INFO((_L("Volume scaled: original %d, scaled %d"), aVol, TInt(tgt))) |
|
279 aVol = TInt(tgt); |
|
280 return err; |
|
281 } |
|
282 |
|
283 // ----------------------------------------------------------------------------- |
|
284 // CBTRCCLegacyVolumeLevelController::RequestCompletedL |
|
285 // ----------------------------------------------------------------------------- |
|
286 // |
|
287 void CBTRCCLegacyVolumeLevelController::RequestCompletedL(CBTRCCActive& aActive, TInt aErr) |
|
288 { |
|
289 TRACE_FUNC |
|
290 if( aActive.ServiceId() == KLegacyVolumeLevelSetServiceId ) |
|
291 { |
|
292 TRACE_INFO( (_L("CBTRCCLegacyVolumeLevelController iState: %d"), iState ) ) |
|
293 if ( aErr != KErrNone ) |
|
294 { |
|
295 // Something wrong happened, could be e.g. the connection has |
|
296 // been released while we are changing volume on remote device. |
|
297 iState = EStateWaitingForVolumeLevelChanges; |
|
298 return; |
|
299 } |
|
300 switch(iState) |
|
301 { |
|
302 case EStateVolumeUp: |
|
303 { |
|
304 ++iCurrentRemoteVolume; |
|
305 break; |
|
306 } |
|
307 case EStateVolumeDown: |
|
308 { |
|
309 --iCurrentRemoteVolume; |
|
310 break; |
|
311 } |
|
312 case EStateDelay: |
|
313 case EStateWaitingForVolumeLevelChanges: |
|
314 case EStateVolumeUpTiming: |
|
315 case EStateVolumeDownTiming: |
|
316 break; |
|
317 default: |
|
318 // Impossible to happen. |
|
319 break; |
|
320 } |
|
321 DoRemoteControl(); |
|
322 } |
|
323 else |
|
324 { |
|
325 // This is something the base class can handle. |
|
326 CBTRCCVolumeLevelControllerBase::RequestCompletedL(aActive, aErr); |
|
327 } |
|
328 } |
|
329 |
|
330 // ----------------------------------------------------------------------------- |
|
331 // CBTRCCLegacyVolumeLevelController::CancelRequest |
|
332 // ----------------------------------------------------------------------------- |
|
333 // |
|
334 void CBTRCCLegacyVolumeLevelController::CancelRequest(TInt aServiceId) |
|
335 { |
|
336 TRACE_FUNC |
|
337 if( aServiceId == KLegacyVolumeLevelSetServiceId ) |
|
338 { |
|
339 // Cancel possible active timers |
|
340 iCtrlRTimer.Cancel(); |
|
341 |
|
342 if (iState == EStateVolumeUp) |
|
343 { |
|
344 ++iCurrentRemoteVolume; |
|
345 } |
|
346 else if (iState == EStateVolumeDown) |
|
347 { |
|
348 --iCurrentRemoteVolume; |
|
349 } |
|
350 } |
|
351 else |
|
352 { |
|
353 // This is something the base class can handle. |
|
354 CBTRCCVolumeLevelControllerBase::CancelRequest(aServiceId); |
|
355 } |
|
356 } |
|
357 |
|
358 // ----------------------------------------------------------------------------- |
|
359 // CBTRCCLegacyVolumeLevelController::StartTimer |
|
360 // ----------------------------------------------------------------------------- |
|
361 // |
|
362 void CBTRCCLegacyVolumeLevelController::StartTimer(TInt aInterval) |
|
363 { |
|
364 TRACE_FUNC |
|
365 if( !iBtrccLegacyVolumeActive->IsActive() ) |
|
366 { |
|
367 iCtrlRTimer.After(iBtrccLegacyVolumeActive->iStatus, aInterval); |
|
368 iBtrccLegacyVolumeActive->GoActive(); |
|
369 } |
|
370 else |
|
371 { |
|
372 TRACE_INFO(_L("CBTRCCLegacyVolumeLevelController::StartTimer() ERR, timer already active!")) |
|
373 } |
|
374 } |
|
375 |
|
376 // ----------------------------------------------------------------------------- |
|
377 // CBTRCCLegacyVolumeLevelController::SendVolumeCommand |
|
378 // ----------------------------------------------------------------------------- |
|
379 // |
|
380 void CBTRCCLegacyVolumeLevelController::SendVolumeCommand(TInt aDirection) |
|
381 { |
|
382 TRACE_FUNC |
|
383 if( !iBtrccLegacyVolumeActive->IsActive() ) |
|
384 { |
|
385 if( aDirection == EStateVolumeUp ) |
|
386 { |
|
387 iRemConVolController->VolumeUp(iBtrccLegacyVolumeActive->iStatus, iNumRemotes, ERemConCoreApiButtonClick); |
|
388 } |
|
389 else |
|
390 { |
|
391 iRemConVolController->VolumeDown(iBtrccLegacyVolumeActive->iStatus, iNumRemotes, ERemConCoreApiButtonClick); |
|
392 } |
|
393 iBtrccLegacyVolumeActive->GoActive(); |
|
394 } |
|
395 else |
|
396 { |
|
397 TRACE_INFO(_L("CBTRCCLegacyVolumeLevelController::DoRemConControl() ERR, previous action ongoing!")) |
|
398 } |
|
399 } |
|
400 |
|
401 // ----------------------------------------------------------------------------- |
|
402 // CBTRCCLegacyVolumeLevelController::MrccacoResponse() |
|
403 // ----------------------------------------------------------------------------- |
|
404 // |
|
405 TInt CBTRCCLegacyVolumeLevelController::MrccacoResponse() |
|
406 { |
|
407 TRACE_FUNC |
|
408 return 0; |
|
409 } |
|
410 |
|
411 // End of File |