OSDN Git Service

(Re)routing Notification API in AudioTrack/AudioRecord.
authorPaul McLean <pmclean@google.com>
Fri, 17 Apr 2015 19:57:47 +0000 (13:57 -0600)
committerPaul McLean <pmclean@google.com>
Thu, 23 Apr 2015 21:38:25 +0000 (15:38 -0600)
Change-Id: If6594df7e3ed4c4a67878f98c05e3153633cf263

api/current.txt
api/system-current.txt
media/java/android/media/AudioRecord.java
media/java/android/media/AudioTrack.java
media/java/android/media/OnAudioRecordRoutingListener.java [new file with mode: 0644]
media/java/android/media/OnAudioTrackRoutingListener.java [new file with mode: 0644]

index 1ce0f57..227a627 100644 (file)
@@ -14900,6 +14900,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();
@@ -14910,6 +14911,7 @@ package android.media {
     method public int getNotificationMarkerPosition();
     method public int getPositionNotificationPeriod();
     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);
@@ -14920,6 +14922,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 void setRecordPositionUpdateListener(android.media.AudioRecord.OnRecordPositionUpdateListener);
@@ -14962,6 +14965,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();
@@ -14979,6 +14983,7 @@ package android.media {
     method public int getPlaybackRate();
     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();
@@ -14987,6 +14992,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);
@@ -16347,6 +16353,14 @@ package android.media {
     method public abstract void onAudioDeviceConnection();
   }
 
+  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();
index 322a04d..23740ec 100644 (file)
@@ -16110,6 +16110,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();
@@ -16120,6 +16121,7 @@ package android.media {
     method public int getNotificationMarkerPosition();
     method public int getPositionNotificationPeriod();
     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);
@@ -16130,6 +16132,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 void setRecordPositionUpdateListener(android.media.AudioRecord.OnRecordPositionUpdateListener);
@@ -16174,6 +16177,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();
@@ -16191,6 +16195,7 @@ package android.media {
     method public int getPlaybackRate();
     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();
@@ -16199,6 +16204,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);
@@ -17562,6 +17568,14 @@ package android.media {
     method public abstract void onAudioDeviceConnection();
   }
 
+  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();
index 3e771f4..9ac394b 100644 (file)
@@ -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 */
@@ -1117,7 +1124,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.
      */
@@ -1158,6 +1165,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
index 6c41a2a..0ab192e 100644 (file)
@@ -21,6 +21,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.nio.NioUtils;
+import java.util.Collection;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -35,6 +36,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;
@@ -174,6 +176,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";
 
 
@@ -222,7 +230,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.
      */
@@ -1216,7 +1224,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;
         }
@@ -1884,6 +1892,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
     //--------------------
@@ -1912,10 +1980,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
@@ -1963,6 +2031,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
@@ -1976,7 +2093,7 @@ public class AudioTrack
             return;
         }
 
-        NativeEventHandlerDelegate delegate = track.mEventHandlerDelegate;
+        NativePositionEventHandlerDelegate delegate = track.mEventHandlerDelegate;
         if (delegate != null) {
             Handler handler = delegate.getHandler();
             if (handler != null) {
diff --git a/media/java/android/media/OnAudioRecordRoutingListener.java b/media/java/android/media/OnAudioRecordRoutingListener.java
new file mode 100644 (file)
index 0000000..8ff41c5
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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);
+}
diff --git a/media/java/android/media/OnAudioTrackRoutingListener.java b/media/java/android/media/OnAudioTrackRoutingListener.java
new file mode 100644 (file)
index 0000000..18c72ef
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 OnAudioTrackRoutingListener {
+    /**
+     * Called when the routing of an AudioTrack changes from either and explicit or
+     * policy rerouting.
+     */
+    public void onAudioTrackRouting(AudioTrack audioTrack);
+}