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

Commit ed36ca3d authored by Paul McLean's avatar Paul McLean
Browse files

Native Audio Routing and (Java) AudioRouting (interface).

Adding AudioRouting (Java) interface for routing control
in AudioTrack and AudioRecord.
Deprecating current (Marshmallow) Routing APIs in
AudioTrack and AudioRecord.
Adding package-private constructors to AudioTrack and AudioRecord
to connect to native player/recorder.

Bug: 23899814
Change-Id: I7df7a687fbd56a34c1f5769ffe005eba2a059505
parent 54f715cb
Loading
Loading
Loading
Loading
+23 −8
Original line number Diff line number Diff line
@@ -19351,9 +19351,10 @@ package android.media {
    method public abstract void onAudioFocusChange(int);
  }
  public class AudioRecord {
  public class AudioRecord implements android.media.AudioRouting {
    ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
    method public void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
    method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public int getAudioFormat();
    method public int getAudioSessionId();
    method public int getAudioSource();
@@ -19377,7 +19378,8 @@ 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 removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
    method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public int setNotificationMarkerPosition(int);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -19415,17 +19417,29 @@ package android.media {
    method public abstract void onRoutingChanged(android.media.AudioRecord);
  }
  public abstract interface AudioRouting {
    method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public abstract android.media.AudioDeviceInfo getPreferredDevice();
    method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
  }
  public static abstract interface AudioRouting.OnRoutingChangedListener {
    method public abstract void onRoutingChanged(android.media.AudioRouting);
  }
  public final class AudioTimestamp {
    ctor public AudioTimestamp();
    field public long framePosition;
    field public long nanoTime;
  }
  public class AudioTrack {
  public class AudioTrack implements android.media.AudioRouting {
    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 addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
    method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public int attachAuxEffect(int);
    method public void flush();
    method public int getAudioFormat();
@@ -19455,7 +19469,8 @@ package android.media {
    method public void play() throws java.lang.IllegalStateException;
    method public void release();
    method public int reloadStaticData();
    method public void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
    method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public int setAuxEffectSendLevel(float);
    method public int setLoopPoints(int, int, int);
    method public int setNotificationMarkerPosition(int);
@@ -19508,8 +19523,8 @@ package android.media {
    method public abstract void onPeriodicNotification(android.media.AudioTrack);
  }
  public static abstract interface AudioTrack.OnRoutingChangedListener {
    method public abstract void onRoutingChanged(android.media.AudioTrack);
  public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
    method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
  }
  public class CamcorderProfile {
+23 −8
Original line number Diff line number Diff line
@@ -20646,10 +20646,11 @@ package android.media {
    method public abstract void onAudioFocusChange(int);
  }
  public class AudioRecord {
  public class AudioRecord implements android.media.AudioRouting {
    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 addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
    method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public int getAudioFormat();
    method public int getAudioSessionId();
    method public int getAudioSource();
@@ -20673,7 +20674,8 @@ 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 removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
    method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public int setNotificationMarkerPosition(int);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -20713,17 +20715,29 @@ package android.media {
    method public abstract void onRoutingChanged(android.media.AudioRecord);
  }
  public abstract interface AudioRouting {
    method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public abstract android.media.AudioDeviceInfo getPreferredDevice();
    method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
  }
  public static abstract interface AudioRouting.OnRoutingChangedListener {
    method public abstract void onRoutingChanged(android.media.AudioRouting);
  }
  public final class AudioTimestamp {
    ctor public AudioTimestamp();
    field public long framePosition;
    field public long nanoTime;
  }
  public class AudioTrack {
  public class AudioTrack implements android.media.AudioRouting {
    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 addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
    method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public int attachAuxEffect(int);
    method public void flush();
    method public int getAudioFormat();
@@ -20753,7 +20767,8 @@ package android.media {
    method public void play() throws java.lang.IllegalStateException;
    method public void release();
    method public int reloadStaticData();
    method public void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
    method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public int setAuxEffectSendLevel(float);
    method public int setLoopPoints(int, int, int);
    method public int setNotificationMarkerPosition(int);
@@ -20806,8 +20821,8 @@ package android.media {
    method public abstract void onPeriodicNotification(android.media.AudioTrack);
  }
  public static abstract interface AudioTrack.OnRoutingChangedListener {
    method public abstract void onRoutingChanged(android.media.AudioTrack);
  public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
    method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
  }
  public class CamcorderProfile {
+23 −8
Original line number Diff line number Diff line
@@ -19359,9 +19359,10 @@ package android.media {
    method public abstract void onAudioFocusChange(int);
  }
  public class AudioRecord {
  public class AudioRecord implements android.media.AudioRouting {
    ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
    method public void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
    method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public int getAudioFormat();
    method public int getAudioSessionId();
    method public int getAudioSource();
@@ -19385,7 +19386,8 @@ 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 removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
    method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public int setNotificationMarkerPosition(int);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -19423,17 +19425,29 @@ package android.media {
    method public abstract void onRoutingChanged(android.media.AudioRecord);
  }
  public abstract interface AudioRouting {
    method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public abstract android.media.AudioDeviceInfo getPreferredDevice();
    method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
  }
  public static abstract interface AudioRouting.OnRoutingChangedListener {
    method public abstract void onRoutingChanged(android.media.AudioRouting);
  }
  public final class AudioTimestamp {
    ctor public AudioTimestamp();
    field public long framePosition;
    field public long nanoTime;
  }
  public class AudioTrack {
  public class AudioTrack implements android.media.AudioRouting {
    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 addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
    method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
    method public int attachAuxEffect(int);
    method public void flush();
    method public int getAudioFormat();
@@ -19463,7 +19477,8 @@ package android.media {
    method public void play() throws java.lang.IllegalStateException;
    method public void release();
    method public int reloadStaticData();
    method public void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
    method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
    method public int setAuxEffectSendLevel(float);
    method public int setLoopPoints(int, int, int);
    method public int setNotificationMarkerPosition(int);
@@ -19516,8 +19531,8 @@ package android.media {
    method public abstract void onPeriodicNotification(android.media.AudioTrack);
  }
  public static abstract interface AudioTrack.OnRoutingChangedListener {
    method public abstract void onRoutingChanged(android.media.AudioTrack);
  public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
    method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
  }
  public class CamcorderProfile {
+169 −26
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ import android.util.Log;
 * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
 * the total recording buffer size.
 */
public class AudioRecord
public class AudioRecord implements AudioRouting
{
    //---------------------------------------------------------
    // Constants
@@ -391,6 +391,20 @@ public class AudioRecord
        mState = STATE_INITIALIZED;
    }

    /**
     * A constructor which explicitly connects a Native (C++) AudioRecord. For use by
     * the AudioRecordRoutingProxy subclass.
     * @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord
     * (associated with an OpenSL ES recorder).
     */
    /*package*/ AudioRecord(long nativeRecordInJavaObj) {
        mNativeRecorderInJavaObj = nativeRecordInJavaObj;

        // other initialization here...

        mState = STATE_INITIALIZED;
    }

    /**
     * Builder class for {@link AudioRecord} objects.
     * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
@@ -1221,23 +1235,6 @@ public class AudioRecord
        return native_set_marker_pos(markerInFrames);
    }


    //--------------------------------------------------------------------------
    // (Re)Routing Info
    //--------------------
    /**
     * Defines the interface by which applications can receive notifications of routing
     * changes for the associated {@link AudioRecord}.
     */
    public interface OnRoutingChangedListener {
        /**
         * Called when the routing of an AudioRecord changes from either and explicit or
         * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from
         * device.
         */
        public void onRoutingChanged(AudioRecord audioRecord);
    }

    /**
     * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
     * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
@@ -1258,6 +1255,89 @@ public class AudioRecord
        return null;
    }

    /*
     * Call BEFORE adding a routing callback handler.
     */
    private void testEnableNativeRoutingCallbacks() {
        if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
            native_enableDeviceCallback();
        }
    }

    /*
     * Call AFTER removing a routing callback handler.
     */
    private void testDisableNativeRoutingCallbacks() {
        if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
            native_disableDeviceCallback();
        }
    }

    //--------------------------------------------------------------------------
    // >= "N" (Re)Routing Info
    //--------------------
    /**
     * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
     * {@link AudioRecord#addOnRoutingListener(AudioRouting.OnRoutingChangedListener,
     *      android.os.Handler)}
     * by an app to receive (re)routing notifications.
     */
    private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>
    mNewRoutingChangeListeners =
        new ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>();

    /**
     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of
     * routing changes on this AudioRecord.
     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
     * notifications of rerouting events.
     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
     * the callback. If <code>null</code>, the {@link Handler} associated with the main
     * {@link Looper} will be used.
     */
    public void addOnRoutingListener(AudioRouting.OnRoutingChangedListener listener,
            android.os.Handler handler) {
        if (listener != null && !mNewRoutingChangeListeners.containsKey(listener)) {
            synchronized (mNewRoutingChangeListeners) {
                testEnableNativeRoutingCallbacks();
                mNewRoutingChangeListeners.put(
                    listener, new NativeNewRoutingEventHandlerDelegate(this, listener,
                            handler != null ? handler : new Handler(mInitializationLooper)));
            }
        }
    }

    /**
     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
    * to receive rerouting notifications.
    * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
    * to remove.
    */
    public void removeOnRoutingListener(AudioRouting.OnRoutingChangedListener listener) {
        synchronized (mNewRoutingChangeListeners) {
            if (mNewRoutingChangeListeners.containsKey(listener)) {
                mNewRoutingChangeListeners.remove(listener);
                testDisableNativeRoutingCallbacks();
            }
        }
    }

    //--------------------------------------------------------------------------
    // Marshmallow (Re)Routing Info
    //--------------------
    /**
     * Defines the interface by which applications can receive notifications of routing
     * changes for the associated {@link AudioRecord}.
     */
    public interface OnRoutingChangedListener {
        /**
         * Called when the routing of an AudioRecord changes from either and explicit or
         * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from
         * device.
         */
        public void onRoutingChanged(AudioRecord audioRecord);
    }

    /**
     * The list of AudioRecord.OnRoutingChangedListener interface added (with
     * {@link AudioRecord#addOnRoutingChangedListener(OnRoutingChangedListener,android.os.Handler)}
@@ -1276,13 +1356,12 @@ public class AudioRecord
     * the callback. If <code>null</code>, the {@link Handler} associated with the main
     * {@link Looper} will be used.
     */
    @Deprecated
    public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
            android.os.Handler handler) {
        if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
            synchronized (mRoutingChangeListeners) {
                if (mRoutingChangeListeners.size() == 0) {
                    native_enableDeviceCallback();
                }
                testEnableNativeRoutingCallbacks();
                mRoutingChangeListeners.put(
                    listener, new NativeRoutingEventHandlerDelegate(this, listener,
                            handler != null ? handler : new Handler(mInitializationLooper)));
@@ -1295,18 +1374,69 @@ public class AudioRecord
     * to receive rerouting notifications.
     * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
     */
    @Deprecated
    public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
        synchronized (mRoutingChangeListeners) {
            if (mRoutingChangeListeners.containsKey(listener)) {
                mRoutingChangeListeners.remove(listener);
                if (mRoutingChangeListeners.size() == 0) {
                    native_disableDeviceCallback();
                testDisableNativeRoutingCallbacks();
            }
        }
    }

    /**
     * >= "N" Routing
     * Helper class to handle the forwarding of native events to the appropriate listener
     * (potentially) handled in a different thread
     */
    private class NativeNewRoutingEventHandlerDelegate {
        private final Handler mHandler;

        NativeNewRoutingEventHandlerDelegate(final AudioRecord record,
                                   final AudioRouting.OnRoutingChangedListener 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 AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
                            if (listener != null) {
                                listener.onRoutingChanged(record);
                            }
                            break;
                        default:
                            loge("Unknown native event type: " + msg.what);
                            break;
                        }
                    }
                };
            } else {
                mHandler = null;
            }
        }

        Handler getHandler() {
            return mHandler;
        }
    }

    /**
     * Marshmallow Routing
     * Helper class to handle the forwarding of native events to the appropriate listener
     * (potentially) handled in a different thread
     */
@@ -1355,21 +1485,34 @@ public class AudioRecord
            return mHandler;
        }
    }

    /**
     * Sends device list change notification to all listeners.
     */
    private void broadcastRoutingChange() {
        AudioManager.resetAudioPortGeneration();
        // Marshmallow Routing
        Collection<NativeRoutingEventHandlerDelegate> values;
        synchronized (mRoutingChangeListeners) {
            values = mRoutingChangeListeners.values();
        }
        AudioManager.resetAudioPortGeneration();
        for(NativeRoutingEventHandlerDelegate delegate : values) {
            Handler handler = delegate.getHandler();
            if (handler != null) {
                handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
            }
        }
        // >= "N" Routing
        Collection<NativeNewRoutingEventHandlerDelegate> newValues;
        synchronized (mNewRoutingChangeListeners) {
            newValues = mNewRoutingChangeListeners.values();
        }
        for(NativeNewRoutingEventHandlerDelegate delegate : newValues) {
            Handler handler = delegate.getHandler();
            if (handler != null) {
                handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
            }
        }
    }

    /**
+32 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 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;

/**
 * An AudioRecord connected to a native (C/C++) which allows access only to routing methods.
 */
class AudioRecordRoutingProxy extends AudioRecord {
    /**
     * A constructor which explicitly connects a Native (C++) AudioRecord. For use by
     * the AudioRecordRoutingProxy subclass.
     * @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord
     * (associated with an OpenSL ES recorder).
     */
    public AudioRecordRoutingProxy(long nativeRecordInJavaObj) {
        super(nativeRecordInJavaObj);
    }
}
Loading