ToneManager.java

  1package eu.siacs.conversations.xmpp.jingle;
  2
  3import android.media.AudioManager;
  4import android.media.ToneGenerator;
  5import android.util.Log;
  6
  7import java.util.Collections;
  8import java.util.Set;
  9import java.util.concurrent.ScheduledFuture;
 10import java.util.concurrent.TimeUnit;
 11
 12import eu.siacs.conversations.Config;
 13
 14import static java.util.Arrays.asList;
 15
 16public class ToneManager {
 17
 18    private final ToneGenerator toneGenerator;
 19
 20    private ToneState state = null;
 21    private ScheduledFuture<?> currentTone;
 22
 23    public ToneManager() {
 24        this.toneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL, 35);
 25    }
 26
 27    public void transition(final boolean isInitiator, final RtpEndUserState state) {
 28        transition(of(isInitiator, state, Collections.emptySet()));
 29    }
 30
 31    public void transition(final boolean isInitiator, final RtpEndUserState state, final Set<Media> media) {
 32        transition(of(isInitiator, state, media));
 33    }
 34
 35    private static ToneState of(final boolean isInitiator, final RtpEndUserState state, final Set<Media> media) {
 36        if (isInitiator) {
 37            if (asList(RtpEndUserState.RINGING, RtpEndUserState.CONNECTING).contains(state)) {
 38                return ToneState.RINGING;
 39            }
 40            if (state == RtpEndUserState.DECLINED_OR_BUSY) {
 41                return ToneState.BUSY;
 42            }
 43        }
 44        if (state == RtpEndUserState.ENDING_CALL) {
 45            if (media.contains(Media.VIDEO)) {
 46                return ToneState.NULL;
 47            } else {
 48                return ToneState.ENDING_CALL;
 49            }
 50        }
 51        if (state == RtpEndUserState.CONNECTED) {
 52            if (media.contains(Media.VIDEO)) {
 53                return ToneState.NULL;
 54            } else {
 55                return ToneState.CONNECTED;
 56            }
 57        }
 58        return ToneState.NULL;
 59    }
 60
 61    private synchronized void transition(ToneState state) {
 62        if (this.state == state) {
 63            return;
 64        }
 65        if (state == ToneState.NULL && this.state == ToneState.ENDING_CALL) {
 66            return;
 67        }
 68        cancelCurrentTone();
 69        Log.d(Config.LOGTAG, getClass().getName() + ".transition(" + state + ")");
 70        switch (state) {
 71            case RINGING:
 72                scheduleWaitingTone();
 73                break;
 74            case CONNECTED:
 75                scheduleConnected();
 76                break;
 77            case BUSY:
 78                scheduleBusy();
 79                break;
 80            case ENDING_CALL:
 81                scheduleEnding();
 82                break;
 83        }
 84        this.state = state;
 85    }
 86
 87    private void scheduleConnected() {
 88        this.currentTone = JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.schedule(() -> {
 89            this.toneGenerator.startTone(ToneGenerator.TONE_CDMA_ONE_MIN_BEEP, 145);
 90        }, 0, TimeUnit.SECONDS);
 91    }
 92
 93    private void scheduleEnding() {
 94        this.currentTone = JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.schedule(() -> {
 95            this.toneGenerator.startTone(ToneGenerator.TONE_CDMA_CALLDROP_LITE, 375);
 96        }, 0, TimeUnit.SECONDS);
 97    }
 98
 99    private void scheduleBusy() {
100        this.currentTone = JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.schedule(() -> {
101            this.toneGenerator.startTone(ToneGenerator.TONE_CDMA_NETWORK_BUSY, 2500);
102        }, 0, TimeUnit.SECONDS);
103    }
104
105    private void scheduleWaitingTone() {
106        this.currentTone = JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.scheduleAtFixedRate(() -> {
107            this.toneGenerator.startTone(ToneGenerator.TONE_CDMA_DIAL_TONE_LITE, 750);
108        }, 0, 3, TimeUnit.SECONDS);
109    }
110
111    private void cancelCurrentTone() {
112        if (currentTone != null) {
113            currentTone.cancel(true);
114        }
115        toneGenerator.stopTone();
116    }
117
118    private enum ToneState {
119        NULL, RINGING, CONNECTED, BUSY, ENDING_CALL
120    }
121}