Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6e6336d authored by Tyler Gunn's avatar Tyler Gunn Committed by android-build-merger
Browse files

Add support for using resource files as incall tones.

am: 87c0eaff

Change-Id: Ib133672f9516f9f09bccb077824d3efd243f10d7
parents d2932af8 87c0eaff
Loading
Loading
Loading
Loading

res/raw/endcall.ogg

0 → 100644
+19.2 KiB

File added.

No diff preview for this file type.

+7 −3
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.ToneGenerator;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -408,8 +409,12 @@ public class CallsManager extends Call.ListenerBase
                        wiredHeadsetManager,
                        mDockManager);

        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        InCallTonePlayer.MediaPlayerFactory mediaPlayerFactory =
                (resourceId, attributes) -> MediaPlayer.create(mContext, resourceId, attributes,
                        audioManager.generateAudioSessionId());
        InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(
                callAudioRoutePeripheralAdapter, lock, toneGeneratorFactory);
                callAudioRoutePeripheralAdapter, lock, toneGeneratorFactory, mediaPlayerFactory);

        SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
        RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context);
@@ -419,8 +424,7 @@ public class CallsManager extends Call.ListenerBase
                emergencyCallHelper);
        mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
                ringtoneFactory, systemVibrator, mInCallController);
        mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext,
                (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE), mLock);
        mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager, mLock);
        mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine,
                this, callAudioModeStateMachineFactory.create((AudioManager)
                        mContext.getSystemService(Context.AUDIO_SERVICE)),
+104 −14
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@

package com.android.server.telecom;

import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.ToneGenerator;
import android.os.Handler;
import android.os.Looper;
@@ -27,9 +29,11 @@ import android.telecom.Logging.Session;
import com.android.internal.annotations.VisibleForTesting;

/**
 * Play a call-related tone (ringback, busy signal, etc.) through ToneGenerator. To use, create an
 * instance using InCallTonePlayer.Factory (passing in the TONE_* constant for the tone you want)
 * and start() it. Implemented on top of {@link Thread} so that the tone plays in its own thread.
 * Play a call-related tone (ringback, busy signal, etc.) either through ToneGenerator, or using a
 * media resource file.
 * To use, create an instance using InCallTonePlayer.Factory (passing in the TONE_* constant for
 * the tone you want) and start() it. Implemented on top of {@link Thread} so that the tone plays in
 * its own thread.
 */
public class InCallTonePlayer extends Thread {

@@ -41,12 +45,15 @@ public class InCallTonePlayer extends Thread {
        private final CallAudioRoutePeripheralAdapter mCallAudioRoutePeripheralAdapter;
        private final TelecomSystem.SyncRoot mLock;
        private final ToneGeneratorFactory mToneGeneratorFactory;
        private final MediaPlayerFactory mMediaPlayerFactory;

        Factory(CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter,
                TelecomSystem.SyncRoot lock, ToneGeneratorFactory toneGeneratorFactory) {
                TelecomSystem.SyncRoot lock, ToneGeneratorFactory toneGeneratorFactory,
                MediaPlayerFactory mediaPlayerFactory) {
            mCallAudioRoutePeripheralAdapter = callAudioRoutePeripheralAdapter;
            mLock = lock;
            mToneGeneratorFactory = toneGeneratorFactory;
            mMediaPlayerFactory = mediaPlayerFactory;
        }

        public void setCallAudioManager(CallAudioManager callAudioManager) {
@@ -55,7 +62,8 @@ public class InCallTonePlayer extends Thread {

        public InCallTonePlayer createPlayer(int tone) {
            return new InCallTonePlayer(tone, mCallAudioManager,
                    mCallAudioRoutePeripheralAdapter, mLock, mToneGeneratorFactory);
                    mCallAudioRoutePeripheralAdapter, mLock, mToneGeneratorFactory,
                    mMediaPlayerFactory);
        }
    }

@@ -63,6 +71,10 @@ public class InCallTonePlayer extends Thread {
        ToneGenerator get (int streamType, int volume);
    }

    public interface MediaPlayerFactory {
        MediaPlayer get (int resourceId, AudioAttributes attributes);
    }

    // The possible tones that we can play.
    public static final int TONE_INVALID = 0;
    public static final int TONE_BUSY = 1;
@@ -80,9 +92,12 @@ public class InCallTonePlayer extends Thread {
    public static final int TONE_VOICE_PRIVACY = 13;
    public static final int TONE_VIDEO_UPGRADE = 14;

    private static final int TONE_RESOURCE_ID_UNDEFINED = -1;

    private static final int RELATIVE_VOLUME_EMERGENCY = 100;
    private static final int RELATIVE_VOLUME_HIPRI = 80;
    private static final int RELATIVE_VOLUME_LOPRI = 50;
    private static final int RELATIVE_VOLUME_UNDEFINED = -1;

    // Buffer time (in msec) to add on to the tone timeout value. Needed mainly when the timeout
    // value for a tone is exact duration of the tone itself.
@@ -111,6 +126,9 @@ public class InCallTonePlayer extends Thread {
    /** Current state of the tone player. */
    private int mState;

    /** For tones which are not generated using ToneGenerator. */
    private MediaPlayer mToneMediaPlayer = null;

    /** Telecom lock object. */
    private final TelecomSystem.SyncRoot mLock;

@@ -118,6 +136,7 @@ public class InCallTonePlayer extends Thread {
    private final Object mSessionLock = new Object();

    private final ToneGeneratorFactory mToneGenerator;
    private final MediaPlayerFactory mMediaPlayerFactory;

    /**
     * Initializes the tone player. Private; use the {@link Factory} to create tone players.
@@ -129,19 +148,20 @@ public class InCallTonePlayer extends Thread {
            CallAudioManager callAudioManager,
            CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter,
            TelecomSystem.SyncRoot lock,
            ToneGeneratorFactory toneGeneratorFactory) {
            ToneGeneratorFactory toneGeneratorFactory,
            MediaPlayerFactory mediaPlayerFactor) {
        mState = STATE_OFF;
        mToneId = toneId;
        mCallAudioManager = callAudioManager;
        mCallAudioRoutePeripheralAdapter = callAudioRoutePeripheralAdapter;
        mLock = lock;
        mToneGenerator = toneGeneratorFactory;
        mMediaPlayerFactory = mediaPlayerFactor;
    }

    /** {@inheritDoc} */
    @Override
    public void run() {
        ToneGenerator toneGenerator = null;
        try {
            synchronized (mSessionLock) {
                if (mSession != null) {
@@ -154,6 +174,8 @@ public class InCallTonePlayer extends Thread {
            final int toneType;  // Passed to ToneGenerator.startTone.
            final int toneVolume;  // Passed to the ToneGenerator constructor.
            final int toneLengthMillis;
            final int mediaResourceId; // The resourceId of the tone to play.  Used for media-based
                                      // tones.

            switch (mToneId) {
                case TONE_BUSY:
@@ -161,11 +183,16 @@ public class InCallTonePlayer extends Thread {
                    toneType = ToneGenerator.TONE_SUP_BUSY;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = 4000;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_CALL_ENDED:
                    toneType = ToneGenerator.TONE_PROP_PROMPT;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = 200;
                    // Don't use tone generator
                    toneType = ToneGenerator.TONE_UNKNOWN;
                    toneVolume = RELATIVE_VOLUME_UNDEFINED;
                    toneLengthMillis = 0;

                    // Use a tone resource file for a more rich, full-bodied tone experience.
                    mediaResourceId = R.raw.endcall;
                    break;
                case TONE_OTA_CALL_ENDED:
                    // TODO: fill in
@@ -174,46 +201,55 @@ public class InCallTonePlayer extends Thread {
                    toneType = ToneGenerator.TONE_SUP_CALL_WAITING;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_CDMA_DROP:
                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
                    toneVolume = RELATIVE_VOLUME_LOPRI;
                    toneLengthMillis = 375;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_CONGESTION:
                    toneType = ToneGenerator.TONE_SUP_CONGESTION;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = 4000;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_INTERCEPT:
                    toneType = ToneGenerator.TONE_CDMA_ABBR_INTERCEPT;
                    toneVolume = RELATIVE_VOLUME_LOPRI;
                    toneLengthMillis = 500;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_OUT_OF_SERVICE:
                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
                    toneVolume = RELATIVE_VOLUME_LOPRI;
                    toneLengthMillis = 375;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_REDIAL:
                    toneType = ToneGenerator.TONE_CDMA_ALERT_AUTOREDIAL_LITE;
                    toneVolume = RELATIVE_VOLUME_LOPRI;
                    toneLengthMillis = 5000;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_REORDER:
                    toneType = ToneGenerator.TONE_CDMA_REORDER;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = 4000;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_RING_BACK:
                    toneType = ToneGenerator.TONE_SUP_RINGTONE;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_UNOBTAINABLE_NUMBER:
                    toneType = ToneGenerator.TONE_SUP_ERROR;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = 4000;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                case TONE_VOICE_PRIVACY:
                    // TODO: fill in.
@@ -223,6 +259,7 @@ public class InCallTonePlayer extends Thread {
                    toneType = ToneGenerator.TONE_SUP_CALL_WAITING;
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = 4000;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    break;
                default:
                    throw new IllegalStateException("Bad toneId: " + mToneId);
@@ -233,16 +270,38 @@ public class InCallTonePlayer extends Thread {
                stream = AudioManager.STREAM_BLUETOOTH_SCO;
            }

            if (toneType != ToneGenerator.TONE_UNKNOWN) {
                playToneGeneratorTone(stream, toneVolume, toneType, toneLengthMillis);
            } else if (mediaResourceId != TONE_RESOURCE_ID_UNDEFINED) {
                playMediaTone(stream, mediaResourceId);
            }
        } finally {
            cleanUpTonePlayer();
            Log.endSession();
        }
    }

    /**
     * Play a tone generated by the {@link ToneGenerator}.
     * @param stream The stream on which the tone will be played.
     * @param toneVolume The volume of the tone.
     * @param toneType The type of tone to play.
     * @param toneLengthMillis How long to play the tone.
     */
    private void playToneGeneratorTone(int stream, int toneVolume, int toneType,
            int toneLengthMillis) {
        ToneGenerator toneGenerator = null;
        try {
            // If the ToneGenerator creation fails, just continue without it. It is a local audio
            // signal, and is not as important.
            try {
                Log.v(this, "Creating generator");
                toneGenerator = mToneGenerator.get(stream, toneVolume);
            } catch (RuntimeException e) {
                Log.w(this, "Failed to create ToneGenerator.", e);
                return;
            }

            Log.i(this, "playToneGeneratorTone: toneType=%d", toneType);
            // TODO: Certain CDMA tones need to check the ringer-volume state before
            // playing. See CallNotifier.InCallTonePlayer.

@@ -267,11 +326,42 @@ public class InCallTonePlayer extends Thread {
            if (toneGenerator != null) {
                toneGenerator.release();
            }
            cleanUpTonePlayer();
            Log.endSession();
        }
    }

    /**
     * Plays an audio-file based media tone.
     * @param stream The audio stream on which to play the tone.
     * @param toneResourceId The resource ID of the tone to play.
     */
    private void playMediaTone(int stream, int toneResourceId) {
        synchronized (this) {
            if (mState != STATE_STOPPED) {
                mState = STATE_ON;
            }
            Log.i(this, "playMediaTone: toneResourceId=%d", toneResourceId);
            AudioAttributes attributes = new AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
                    .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                    .setLegacyStreamType(stream)
                    .build();
            mToneMediaPlayer = mMediaPlayerFactory.get(toneResourceId, attributes);
            mToneMediaPlayer.setLooping(false);
            mToneMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    synchronized (this) {
                        mState = STATE_OFF;
                    }
                    mToneMediaPlayer.release();
                    mToneMediaPlayer = null;
                }
            });
            mToneMediaPlayer.start();
        }

    }

    @VisibleForTesting
    public void startTone() {
        sTonesPlaying++;