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

Commit e56f57c3 authored by Paul McLean's avatar Paul McLean Committed by Android (Google) Code Review
Browse files

Merge "(Re)routing Notification API in AudioTrack/AudioRecord."

parents ec4097b0 d5bad53a
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -14924,6 +14924,7 @@ package android.media {
  public class AudioRecord {
    ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
    method public void addOnAudioRecordRoutingListener(android.media.OnAudioRecordRoutingListener, android.os.Handler);
    method public int getAudioFormat();
    method public int getAudioSessionId();
    method public int getAudioSource();
@@ -14935,6 +14936,7 @@ package android.media {
    method public int getPositionNotificationPeriod();
    method public android.media.AudioDeviceInfo getPreferredInputDevice();
    method public int getRecordingState();
    method public android.media.AudioDeviceInfo getRoutedDevice();
    method public int getSampleRate();
    method public int getState();
    method public int read(byte[], int, int);
@@ -14945,6 +14947,7 @@ package android.media {
    method public int read(java.nio.ByteBuffer, int);
    method public int read(java.nio.ByteBuffer, int, int);
    method public void release();
    method public void removeOnAudioRecordRoutingListener(android.media.OnAudioRecordRoutingListener);
    method public int setNotificationMarkerPosition(int);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredInputDevice(android.media.AudioDeviceInfo);
@@ -14988,6 +14991,7 @@ package android.media {
    ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
    ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
    ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
    method public void addOnAudioTrackRoutingListener(android.media.OnAudioTrackRoutingListener, android.os.Handler);
    method public int attachAuxEffect(int);
    method public void flush();
    method public int getAudioFormat();
@@ -15006,6 +15010,7 @@ package android.media {
    method public android.media.PlaybackSettings getPlaybackSettings();
    method public int getPositionNotificationPeriod();
    method public android.media.AudioDeviceInfo getPreferredOutputDevice();
    method public android.media.AudioDeviceInfo getRoutedDevice();
    method public int getSampleRate();
    method public int getState();
    method public int getStreamType();
@@ -15014,6 +15019,7 @@ package android.media {
    method public void play() throws java.lang.IllegalStateException;
    method public void release();
    method public int reloadStaticData();
    method public void removeOnAudioTrackRoutingListener(android.media.OnAudioTrackRoutingListener);
    method public int setAuxEffectSendLevel(float);
    method public int setLoopPoints(int, int, int);
    method public int setNotificationMarkerPosition(int);
@@ -16427,6 +16433,14 @@ package android.media {
    field public static final int AUDIO_STRETCH_MODE_VOICE = 1; // 0x1
  }
  public abstract interface OnAudioRecordRoutingListener {
    method public abstract void onAudioRecordRouting(android.media.AudioRecord);
  }
  public abstract interface OnAudioTrackRoutingListener {
    method public abstract void onAudioTrackRouting(android.media.AudioTrack);
  }
  public final class Rating implements android.os.Parcelable {
    method public int describeContents();
    method public float getPercentRating();
+14 −0
Original line number Diff line number Diff line
@@ -16135,6 +16135,7 @@ package android.media {
  public class AudioRecord {
    ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
    ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
    method public void addOnAudioRecordRoutingListener(android.media.OnAudioRecordRoutingListener, android.os.Handler);
    method public int getAudioFormat();
    method public int getAudioSessionId();
    method public int getAudioSource();
@@ -16146,6 +16147,7 @@ package android.media {
    method public int getPositionNotificationPeriod();
    method public android.media.AudioDeviceInfo getPreferredInputDevice();
    method public int getRecordingState();
    method public android.media.AudioDeviceInfo getRoutedDevice();
    method public int getSampleRate();
    method public int getState();
    method public int read(byte[], int, int);
@@ -16156,6 +16158,7 @@ package android.media {
    method public int read(java.nio.ByteBuffer, int);
    method public int read(java.nio.ByteBuffer, int, int);
    method public void release();
    method public void removeOnAudioRecordRoutingListener(android.media.OnAudioRecordRoutingListener);
    method public int setNotificationMarkerPosition(int);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredInputDevice(android.media.AudioDeviceInfo);
@@ -16201,6 +16204,7 @@ package android.media {
    ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
    ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
    ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
    method public void addOnAudioTrackRoutingListener(android.media.OnAudioTrackRoutingListener, android.os.Handler);
    method public int attachAuxEffect(int);
    method public void flush();
    method public int getAudioFormat();
@@ -16219,6 +16223,7 @@ package android.media {
    method public android.media.PlaybackSettings getPlaybackSettings();
    method public int getPositionNotificationPeriod();
    method public android.media.AudioDeviceInfo getPreferredOutputDevice();
    method public android.media.AudioDeviceInfo getRoutedDevice();
    method public int getSampleRate();
    method public int getState();
    method public int getStreamType();
@@ -16227,6 +16232,7 @@ package android.media {
    method public void play() throws java.lang.IllegalStateException;
    method public void release();
    method public int reloadStaticData();
    method public void removeOnAudioTrackRoutingListener(android.media.OnAudioTrackRoutingListener);
    method public int setAuxEffectSendLevel(float);
    method public int setLoopPoints(int, int, int);
    method public int setNotificationMarkerPosition(int);
@@ -17643,6 +17649,14 @@ package android.media {
    field public static final int AUDIO_STRETCH_MODE_VOICE = 1; // 0x1
  }
  public abstract interface OnAudioRecordRoutingListener {
    method public abstract void onAudioRecordRouting(android.media.AudioRecord);
  }
  public abstract interface OnAudioTrackRoutingListener {
    method public abstract void onAudioTrackRouting(android.media.AudioTrack);
  }
  public final class Rating implements android.os.Parcelable {
    method public int describeContents();
    method public float getPercentRating();
+117 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Iterator;

import android.annotation.IntDef;
@@ -32,6 +33,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;

/**
@@ -113,6 +115,11 @@ public class AudioRecord
     */
    private static final int NATIVE_EVENT_NEW_POS = 3;

    /**
     * Event id denotes when the routing changes.
     */
    private final static int NATIVE_EVENT_ROUTING_CHANGE = 1000;

    private final static String TAG = "android.media.AudioRecord";

    /** @hide */
@@ -1127,7 +1134,7 @@ public class AudioRecord
     * Sets the listener the AudioRecord notifies when a previously set marker is reached or
     * for each periodic record head position update.
     * Use this method to receive AudioRecord events in the Handler associated with another
     * thread than the one in which you created the AudioTrack instance.
     * thread than the one in which you created the AudioRecord instance.
     * @param listener
     * @param handler the Handler that will receive the event notification messages.
     */
@@ -1168,6 +1175,115 @@ public class AudioRecord
    }


    //--------------------------------------------------------------------------
    // (Re)Routing Info
    //--------------------
    /**
     * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
     */
    public AudioDeviceInfo getRoutedDevice() {
        return null;
    }

    /**
     * The message sent to apps when the routing of this AudioRecord changes if they provide
     * a {#link Handler} object to addOnAudioRecordRoutingListener().
     */
    private ArrayMap<OnAudioRecordRoutingListener, NativeRoutingEventHandlerDelegate>
        mRoutingChangeListeners =
            new ArrayMap<OnAudioRecordRoutingListener, NativeRoutingEventHandlerDelegate>();

    /**
     * Adds an {@link OnAudioRecordRoutingListener} to receive notifications of routing changes
     * on this AudioRecord.
     */
    public void addOnAudioRecordRoutingListener(OnAudioRecordRoutingListener listener,
            android.os.Handler handler) {
        if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
            synchronized (mRoutingChangeListeners) {
                mRoutingChangeListeners.put(
                    listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
            }
        }
    }

    /**
     * Removes an {@link OnAudioRecordRoutingListener} which has been previously added
     * to receive notifications of changes to the set of connected audio devices.
     */
    public void removeOnAudioRecordRoutingListener(OnAudioRecordRoutingListener listener) {
        synchronized (mRoutingChangeListeners) {
            if (mRoutingChangeListeners.containsKey(listener)) {
                mRoutingChangeListeners.remove(listener);
            }
        }
    }

    /**
     * Helper class to handle the forwarding of native events to the appropriate listener
     * (potentially) handled in a different thread
     */
    private class NativeRoutingEventHandlerDelegate {
        private final Handler mHandler;

        NativeRoutingEventHandlerDelegate(final AudioRecord record,
                                   final OnAudioRecordRoutingListener listener,
                                   Handler handler) {
            // find the looper for our new event handler
            Looper looper;
            if (handler != null) {
                looper = handler.getLooper();
            } else {
                // no given handler, use the looper the AudioRecord was created in
                looper = mInitializationLooper;
            }

            // construct the event handler with this looper
            if (looper != null) {
                // implement the event handler delegate
                mHandler = new Handler(looper) {
                    @Override
                    public void handleMessage(Message msg) {
                        if (record == null) {
                            return;
                        }
                        switch(msg.what) {
                        case NATIVE_EVENT_ROUTING_CHANGE:
                            if (listener != null) {
                                listener.onAudioRecordRouting(record);
                            }
                            break;
                        default:
                            loge("Unknown native event type: " + msg.what);
                            break;
                        }
                    }
                };
            } else {
                mHandler = null;
            }
        }

        Handler getHandler() {
            return mHandler;
        }
    }
    /**
     * Sends device list change notification to all listeners.
     */
    private void broadcastRoutingChange() {
        Collection<NativeRoutingEventHandlerDelegate> values;
        synchronized (mRoutingChangeListeners) {
            values = mRoutingChangeListeners.values();
        }
        for(NativeRoutingEventHandlerDelegate delegate : values) {
            Handler handler = delegate.getHandler();
            if (handler != null) {
                handler.sendEmptyMessage(NATIVE_EVENT_ROUTING_CHANGE);
            }
        }
    }

    /**
     * Sets the period at which the listener is called, if set with
     * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
+122 −5
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import java.lang.Math;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.NioUtils;
import java.util.Collection;

import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -37,6 +38,7 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;

import com.android.internal.app.IAppOpsService;
@@ -176,6 +178,12 @@ public class AudioTrack
     */
    private static final int NATIVE_EVENT_NEW_POS = 4;

    /**
     * Event id denotes when the routing changes.
     */
    private final static int NATIVE_EVENT_ROUTING_CHANGE = 1000;


    private final static String TAG = "android.media.AudioTrack";


@@ -224,7 +232,7 @@ public class AudioTrack
    /**
     * Handler for events coming from the native code.
     */
    private NativeEventHandlerDelegate mEventHandlerDelegate;
    private NativePositionEventHandlerDelegate mEventHandlerDelegate;
    /**
     * Looper associated with the thread that creates the AudioTrack instance.
     */
@@ -1243,7 +1251,7 @@ public class AudioTrack
    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
                                                    Handler handler) {
        if (listener != null) {
            mEventHandlerDelegate = new NativeEventHandlerDelegate(this, listener, handler);
            mEventHandlerDelegate = new NativePositionEventHandlerDelegate(this, listener, handler);
        } else {
            mEventHandlerDelegate = null;
        }
@@ -2109,6 +2117,66 @@ public class AudioTrack
        return mPreferredDevice;
    }

    //--------------------------------------------------------------------------
    // (Re)Routing Info
    //--------------------
    /**
     * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack.
     */
    public AudioDeviceInfo getRoutedDevice() {
        return null;
    }

    /**
     * The message sent to apps when the routing of this AudioTrack changes if they provide
     * a {#link Handler} object to addOnAudioTrackRoutingListener().
     */
    private ArrayMap<OnAudioTrackRoutingListener, NativeRoutingEventHandlerDelegate>
        mRoutingChangeListeners =
            new ArrayMap<OnAudioTrackRoutingListener, NativeRoutingEventHandlerDelegate>();

    /**
     * Adds an {@link OnAudioTrackRoutingListener} to receive notifications of routing changes
     * on this AudioTrack.
     */
    public void addOnAudioTrackRoutingListener(OnAudioTrackRoutingListener listener,
            android.os.Handler handler) {
        if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
            synchronized (mRoutingChangeListeners) {
                mRoutingChangeListeners.put(
                    listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
            }
        }
    }

    /**
     * Removes an {@link OnAudioTrackRoutingListener} which has been previously added
     * to receive notifications of changes to the set of connected audio devices.
     */
    public void removeOnAudioTrackRoutingListener(OnAudioTrackRoutingListener listener) {
        synchronized (mRoutingChangeListeners) {
            if (mRoutingChangeListeners.containsKey(listener)) {
                mRoutingChangeListeners.remove(listener);
            }
        }
    }

    /**
     * Sends device list change notification to all listeners.
     */
    private void broadcastRoutingChange() {
        Collection<NativeRoutingEventHandlerDelegate> values;
        synchronized (mRoutingChangeListeners) {
            values = mRoutingChangeListeners.values();
        }
        for(NativeRoutingEventHandlerDelegate delegate : values) {
            Handler handler = delegate.getHandler();
            if (handler != null) {
                handler.sendEmptyMessage(NATIVE_EVENT_ROUTING_CHANGE);
            }
        }
    }

    //---------------------------------------------------------
    // Interface definitions
    //--------------------
@@ -2137,10 +2205,10 @@ public class AudioTrack
     * Helper class to handle the forwarding of native events to the appropriate listener
     * (potentially) handled in a different thread
     */
    private class NativeEventHandlerDelegate {
    private class NativePositionEventHandlerDelegate {
        private final Handler mHandler;

        NativeEventHandlerDelegate(final AudioTrack track,
        NativePositionEventHandlerDelegate(final AudioTrack track,
                                   final OnPlaybackPositionUpdateListener listener,
                                   Handler handler) {
            // find the looper for our new event handler
@@ -2188,6 +2256,55 @@ public class AudioTrack
        }
    }

    /**
     * Helper class to handle the forwarding of native events to the appropriate listener
     * (potentially) handled in a different thread
     */
    private class NativeRoutingEventHandlerDelegate {
        private final Handler mHandler;

        NativeRoutingEventHandlerDelegate(final AudioTrack track,
                                   final OnAudioTrackRoutingListener listener,
                                   Handler handler) {
            // find the looper for our new event handler
            Looper looper;
            if (handler != null) {
                looper = handler.getLooper();
            } else {
                // no given handler, use the looper the AudioTrack was created in
                looper = mInitializationLooper;
            }

            // construct the event handler with this looper
            if (looper != null) {
                // implement the event handler delegate
                mHandler = new Handler(looper) {
                    @Override
                    public void handleMessage(Message msg) {
                        if (track == null) {
                            return;
                        }
                        switch(msg.what) {
                        case NATIVE_EVENT_ROUTING_CHANGE:
                            if (listener != null) {
                                listener.onAudioTrackRouting(track);
                            }
                            break;
                        default:
                            loge("Unknown native event type: " + msg.what);
                            break;
                        }
                    }
                };
            } else {
                mHandler = null;
            }
        }

        Handler getHandler() {
            return mHandler;
        }
    }

    //---------------------------------------------------------
    // Java methods called from the native side
@@ -2201,7 +2318,7 @@ public class AudioTrack
            return;
        }

        NativeEventHandlerDelegate delegate = track.mEventHandlerDelegate;
        NativePositionEventHandlerDelegate delegate = track.mEventHandlerDelegate;
        if (delegate != null) {
            Handler handler = delegate.getHandler();
            if (handler != null) {
+29 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

/**
 * OnAudioDeviceConnectionListener defines the interface for notification listeners in the
 * {@link AudioDevicesManager}
 */
public interface OnAudioRecordRoutingListener {
    /**
     * Called when the routing of an AudioRecord changes from either and explicit or
     * policy rerouting.
     */
    public void onAudioRecordRouting(AudioRecord audioRecord);
}
Loading