1 /* 2 * Copyright 2014, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.telecom; 18 19 import com.android.internal.util.Preconditions; 20 21 /** 22 * Plays ringback tones. Ringback is different from other tones because it operates as the current 23 * audio for a call, whereas most tones play as simple timed events. This means ringback must be 24 * able to turn off and on as the user switches between calls. This is why it is implemented as its 25 * own class. 26 */ 27 class RingbackPlayer extends CallsManagerListenerBase { 28 29 private final CallsManager mCallsManager; 30 31 private final InCallTonePlayer.Factory mPlayerFactory; 32 33 /** 34 * The current call for which the ringback tone is being played. 35 */ 36 private Call mCall; 37 38 /** 39 * The currently active player. 40 */ 41 private InCallTonePlayer mTonePlayer; 42 43 RingbackPlayer(CallsManager callsManager, InCallTonePlayer.Factory playerFactory) { 44 mCallsManager = callsManager; 45 mPlayerFactory = playerFactory; 46 } 47 48 /** {@inheritDoc} */ 49 @Override 50 public void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall) { 51 if (oldForegroundCall != null) { 52 stopRingbackForCall(oldForegroundCall); 53 } 54 55 if (shouldStartRinging(newForegroundCall)) { 56 startRingbackForCall(newForegroundCall); 57 } 58 } 59 60 @Override 61 public void onConnectionServiceChanged( 62 Call call, 63 ConnectionServiceWrapper oldService, 64 ConnectionServiceWrapper newService) { 65 66 // Treat as ending or begining dialing based on the state transition. 67 if (shouldStartRinging(call)) { 68 startRingbackForCall(call); 69 } else if (newService == null) { 70 stopRingbackForCall(call); 71 } 72 } 73 74 @Override 75 public void onRingbackRequested(Call call, boolean ignored) { 76 if (shouldStartRinging(call)) { 77 startRingbackForCall(call); 78 } else { 79 stopRingbackForCall(call); 80 } 81 } 82 83 /** 84 * Starts ringback for the specified dialing call as needed. 85 * 86 * @param call The call for which to ringback. 87 */ 88 private void startRingbackForCall(Call call) { 89 Preconditions.checkState(call.getState() == CallState.DIALING); 90 91 if (mCall == call) { 92 Log.w(this, "Ignoring duplicate requests to ring for %s.", call); 93 return; 94 } 95 96 if (mCall != null) { 97 // We only get here for the foreground call so, there's no reason why there should 98 // exist a current dialing call. 99 Log.wtf(this, "Ringback player thinks there are two foreground-dialing calls."); 100 } 101 102 mCall = call; 103 if (mTonePlayer == null) { 104 Log.d(this, "Playing the ringback tone for %s.", call); 105 mTonePlayer = mPlayerFactory.createPlayer(InCallTonePlayer.TONE_RING_BACK); 106 mTonePlayer.startTone(); 107 } 108 } 109 110 /** 111 * Stops the ringback for the specified dialing call as needed. 112 * 113 * @param call The call for which to stop ringback. 114 */ 115 private void stopRingbackForCall(Call call) { 116 if (mCall == call) { 117 // The foreground call is no longer dialing or is no longer the foreground call. In 118 // either case, stop the ringback tone. 119 mCall = null; 120 121 if (mTonePlayer == null) { 122 Log.w(this, "No player found to stop."); 123 } else { 124 Log.i(this, "Stopping the ringback tone for %s.", call); 125 mTonePlayer.stopTone(); 126 mTonePlayer = null; 127 } 128 } 129 } 130 131 private boolean shouldStartRinging(Call call) { 132 return call != null 133 && mCallsManager.getForegroundCall() == call 134 && call.getState() == CallState.DIALING 135 && call.isRingbackRequested(); 136 } 137 } 138