Home | History | Annotate | Download | only in telecom
      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