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

Unverified Commit b6657ca0 authored by Matt Garnes's avatar Matt Garnes Committed by Michael Bestas
Browse files

Add broadcast and query API for AudioSource.HOTWORD.

- When the AudioSource.HOTWORD input becomes active or is released, send
  a Broadcast with the package name and the new state of the audio input
  to any applications that hold CAPTURE_AUDIO_OUTPUT.
- Store the package name of the application that controls the hOTWORD
  input or set it to null if the input is not in use.
- Add a new method to AudioService to retrieve the package name of the
  application that currently controls the HOTWORD input.

Change-Id: I2f11888f3711d23b6287a4de7b81d361734a8f3b
parent fdcb0e39
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -994,6 +994,11 @@ public class AudioRecord implements AudioRouting
                mRecordingState = RECORDSTATE_RECORDING;
            }
        }

        if (getRecordingState() == RECORDSTATE_RECORDING &&
                getAudioSource() == MediaRecorder.AudioSource.HOTWORD) {
            handleHotwordInput(true);
        }
    }

    /**
@@ -1036,6 +1041,10 @@ public class AudioRecord implements AudioRouting
            native_stop();
            mRecordingState = RECORDSTATE_STOPPED;
        }

        if (getAudioSource() == MediaRecorder.AudioSource.HOTWORD) {
            handleHotwordInput(false);
        }
    }

    private final IBinder mICallBack = new Binder();
@@ -1052,6 +1061,16 @@ public class AudioRecord implements AudioRouting
        }
    }

    private void handleHotwordInput(boolean listening) {
        final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
        final IAudioService ias = IAudioService.Stub.asInterface(b);
        try {
            ias.handleHotwordInput(listening);
        } catch (RemoteException e) {
            Log.e(TAG, "Error talking to AudioService when handling hotword input.", e);
        }
    }

    //---------------------------------------------------------
    // Audio data supply
    //--------------------
+4 −0
Original line number Diff line number Diff line
@@ -166,6 +166,10 @@ interface IAudioService {

    List<AudioRecordingConfiguration> getActiveRecordingConfigurations();

    void handleHotwordInput(boolean listening);

    String getCurrentHotwordInputPackageName();

    void updateRemoteControllerOnExistingMediaPlayers();

    void addMediaPlayerAndUpdateRemoteController(String packageName);
+59 −1
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import static android.os.Process.FIRST_APPLICATION_UID;

import static cyanogenmod.media.MediaRecorder.ACTION_HOTWORD_INPUT_CHANGED;
import static cyanogenmod.media.MediaRecorder.EXTRA_CURRENT_PACKAGE_NAME;
import static cyanogenmod.media.MediaRecorder.EXTRA_HOTWORD_INPUT_STATE;

import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -60,6 +64,7 @@ import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioPort;
import android.media.AudioRecord;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
@@ -406,6 +411,15 @@ public class AudioService extends IAudioService.Stub {
     * @see System#MUTE_STREAMS_AFFECTED */
    private int mMuteAffectedStreams;

    /** @see #handleHotwordInput **/
    private Object mHotwordInputLock = new Object();

    /** The package name of the application that is
     * currently using the HOTWORD input.
     */
    // protected by mHotwordInputLock
    private String mHotwordAudioInputPackage;

    /**
     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
     * mVibrateSetting is just maintained during deprecation period but vibration policy is
@@ -1747,6 +1761,46 @@ public class AudioService extends IAudioService.Stub {
        return true;
    }

    /**
     * Retrieve the package name of the application that currently controls
     * the {@link android.media.MediaRecorder.AudioSource#HOTWORD} input.
     * @return The package name of the application that controls the input
     * or null if no package currently controls it.
     */
    public String getCurrentHotwordInputPackageName() {
        return mHotwordAudioInputPackage;
    }

    /**
     * Handle the change of state of the HOTWORD input.
     *
     * When the {@link android.media.MediaRecorder.AudioSource#HOTWORD} input is
     * in use, send a broadcast to alert the new state and store the name of the current
     * package that controls the input in mHotwordAudioInputPackage.
     * @param listening Whether the input is being listened to.
     */
    public void handleHotwordInput(boolean listening) {
        synchronized (mHotwordInputLock) {
            Intent broadcastIntent = new Intent(ACTION_HOTWORD_INPUT_CHANGED);
            String[] packages = mContext.getPackageManager().getPackagesForUid(
                    Binder.getCallingUid());
            if (packages.length > 0) {
                if (listening) {
                    mHotwordAudioInputPackage = packages[0];
                }
                broadcastIntent.putExtra(EXTRA_CURRENT_PACKAGE_NAME, packages[0]);
            }
            broadcastIntent.putExtra(EXTRA_HOTWORD_INPUT_STATE,
                                     listening ? AudioRecord.RECORDSTATE_RECORDING :
                                     AudioRecord.RECORDSTATE_STOPPED);
            // Set the currently listening package to null if listening has stopped.
            if (!listening) {
                mHotwordAudioInputPackage = null;
            }
            sendBroadcastToAll(broadcastIntent, Manifest.permission.CAPTURE_AUDIO_HOTWORD);
        }
    }

    /** @see AudioManager#forceVolumeControlStream(int) */
    public void forceVolumeControlStream(int streamType, IBinder cb) {
        synchronized(mForceControlStreamLock) {
@@ -1799,11 +1853,15 @@ public class AudioService extends IAudioService.Stub {
    }

    private void sendBroadcastToAll(Intent intent) {
        sendBroadcastToAll(intent, null);
    }

    private void sendBroadcastToAll(Intent intent, String receiverPermission) {
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        final long ident = Binder.clearCallingIdentity();
        try {
            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
            mContext.sendBroadcastAsUser(intent, UserHandle.ALL, receiverPermission);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }