From ed2edc7a8e044e31a6c9db638c97f9c21fb1d946 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 11 Apr 2016 10:57:50 -0600 Subject: [PATCH] Clean up AudioRouting API internals. Reuse existing OnRoutingChangedListener APIs and internal logic by extending the new AudioRouting.OnRoutingChangedListener. We use new default methods to delegate incoming calls on the legacy interfaces. Fix a handful of locking bugs. Bug: 27950070, 27952052, 27949198 Change-Id: Ie584108bcbeeab064d8e27d4984e541f31d36728 --- api/current.txt | 20 ++- api/system-current.txt | 20 ++- api/test-current.txt | 20 ++- media/java/android/media/AudioRecord.java | 188 +++++++-------------- media/java/android/media/AudioRouting.java | 4 +- media/java/android/media/AudioTrack.java | 183 +++++++------------- 6 files changed, 153 insertions(+), 282 deletions(-) diff --git a/api/current.txt b/api/current.txt index 34445974ba2a8..3eacdc8b8a3d7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -19852,8 +19852,8 @@ package android.media { 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.AudioRouting.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(); @@ -19878,8 +19878,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.AudioRouting.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); @@ -19913,8 +19913,9 @@ package android.media { method public abstract void onPeriodicNotification(android.media.AudioRecord); } - public static abstract interface AudioRecord.OnRoutingChangedListener { + public static abstract deprecated interface AudioRecord.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener { method public abstract void onRoutingChanged(android.media.AudioRecord); + method public default void onRoutingChanged(android.media.AudioRouting); } public final class AudioRecordingConfiguration implements android.os.Parcelable { @@ -19929,10 +19930,10 @@ package android.media { } public abstract interface AudioRouting { - method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); + method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public abstract android.media.AudioDeviceInfo getPreferredDevice(); method public abstract android.media.AudioDeviceInfo getRoutedDevice(); - method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener); + method public abstract void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo); } @@ -19952,8 +19953,8 @@ 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 addOnRoutingChangedListener(android.media.AudioRouting.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(); @@ -19985,8 +19986,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.AudioRouting.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 setBufferSizeInFrames(int); method public int setLoopPoints(int, int, int); @@ -20040,8 +20041,9 @@ package android.media { method public abstract void onPeriodicNotification(android.media.AudioTrack); } - public static abstract deprecated interface AudioTrack.OnRoutingChangedListener { - method public abstract deprecated void onRoutingChanged(android.media.AudioTrack); + public static abstract deprecated interface AudioTrack.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener { + method public abstract void onRoutingChanged(android.media.AudioTrack); + method public default void onRoutingChanged(android.media.AudioRouting); } public class CamcorderProfile { diff --git a/api/system-current.txt b/api/system-current.txt index a4927f2ac578f..01e0fde8354a5 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -21330,8 +21330,8 @@ package android.media { 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.AudioRouting.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(); @@ -21356,8 +21356,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.AudioRouting.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); @@ -21393,8 +21393,9 @@ package android.media { method public abstract void onPeriodicNotification(android.media.AudioRecord); } - public static abstract interface AudioRecord.OnRoutingChangedListener { + public static abstract deprecated interface AudioRecord.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener { method public abstract void onRoutingChanged(android.media.AudioRecord); + method public default void onRoutingChanged(android.media.AudioRouting); } public final class AudioRecordingConfiguration implements android.os.Parcelable { @@ -21409,10 +21410,10 @@ package android.media { } public abstract interface AudioRouting { - method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); + method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public abstract android.media.AudioDeviceInfo getPreferredDevice(); method public abstract android.media.AudioDeviceInfo getRoutedDevice(); - method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener); + method public abstract void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo); } @@ -21432,8 +21433,8 @@ 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 addOnRoutingChangedListener(android.media.AudioRouting.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(); @@ -21465,8 +21466,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.AudioRouting.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 setBufferSizeInFrames(int); method public int setLoopPoints(int, int, int); @@ -21520,8 +21521,9 @@ package android.media { method public abstract void onPeriodicNotification(android.media.AudioTrack); } - public static abstract deprecated interface AudioTrack.OnRoutingChangedListener { - method public abstract deprecated void onRoutingChanged(android.media.AudioTrack); + public static abstract deprecated interface AudioTrack.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener { + method public abstract void onRoutingChanged(android.media.AudioTrack); + method public default void onRoutingChanged(android.media.AudioRouting); } public class CamcorderProfile { diff --git a/api/test-current.txt b/api/test-current.txt index 41799480a6689..9fb6e245e0694 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -19918,8 +19918,8 @@ package android.media { 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.AudioRouting.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(); @@ -19944,8 +19944,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.AudioRouting.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); @@ -19979,8 +19979,9 @@ package android.media { method public abstract void onPeriodicNotification(android.media.AudioRecord); } - public static abstract interface AudioRecord.OnRoutingChangedListener { + public static abstract deprecated interface AudioRecord.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener { method public abstract void onRoutingChanged(android.media.AudioRecord); + method public default void onRoutingChanged(android.media.AudioRouting); } public final class AudioRecordingConfiguration implements android.os.Parcelable { @@ -19995,10 +19996,10 @@ package android.media { } public abstract interface AudioRouting { - method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); + method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public abstract android.media.AudioDeviceInfo getPreferredDevice(); method public abstract android.media.AudioDeviceInfo getRoutedDevice(); - method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener); + method public abstract void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo); } @@ -20018,8 +20019,8 @@ 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 addOnRoutingChangedListener(android.media.AudioRouting.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(); @@ -20051,8 +20052,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.AudioRouting.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 setBufferSizeInFrames(int); method public int setLoopPoints(int, int, int); @@ -20106,8 +20107,9 @@ package android.media { method public abstract void onPeriodicNotification(android.media.AudioTrack); } - public static abstract deprecated interface AudioTrack.OnRoutingChangedListener { - method public abstract deprecated void onRoutingChanged(android.media.AudioTrack); + public static abstract deprecated interface AudioTrack.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener { + method public abstract void onRoutingChanged(android.media.AudioTrack); + method public default void onRoutingChanged(android.media.AudioRouting); } public class CamcorderProfile { diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index ca306cc7127cd..a5550ec7248bf 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -37,6 +37,8 @@ import android.os.ServiceManager; import android.util.ArrayMap; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + /** * The AudioRecord class manages the audio resources for Java applications * to record audio from the audio input hardware of the platform. This is @@ -1320,6 +1322,7 @@ public class AudioRecord implements AudioRouting * Note: The query is only valid if the AudioRecord is currently recording. If it is not, * getRoutedDevice() will return null. */ + @Override public AudioDeviceInfo getRoutedDevice() { int deviceId = native_getRoutedDeviceId(); if (deviceId == 0) { @@ -1338,8 +1341,8 @@ public class AudioRecord implements AudioRouting /* * Call BEFORE adding a routing callback handler. */ - private void testEnableNativeRoutingCallbacks() { - if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) { + private void testEnableNativeRoutingCallbacksLocked() { + if (mRoutingChangeListeners.size() == 0) { native_enableDeviceCallback(); } } @@ -1347,24 +1350,23 @@ public class AudioRecord implements AudioRouting /* * Call AFTER removing a routing callback handler. */ - private void testDisableNativeRoutingCallbacks() { - if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) { + private void testDisableNativeRoutingCallbacksLocked() { + if (mRoutingChangeListeners.size() == 0) { native_disableDeviceCallback(); } } //-------------------------------------------------------------------------- - // >= "N" (Re)Routing Info + // (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. + * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive + * (re)routing notifications. */ - private ArrayMap - mNewRoutingChangeListeners = - new ArrayMap(); + @GuardedBy("mRoutingChangeListeners") + private ArrayMap mRoutingChangeListeners = new ArrayMap<>(); /** * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of @@ -1375,14 +1377,15 @@ public class AudioRecord implements AudioRouting * the callback. If null, the {@link Handler} associated with the main * {@link Looper} will be used. */ - public void addOnRoutingListener(AudioRouting.OnRoutingChangedListener listener, + @Override + public void addOnRoutingChangedListener(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))); + synchronized (mRoutingChangeListeners) { + if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { + testEnableNativeRoutingCallbacksLocked(); + mRoutingChangeListeners.put( + listener, new NativeRoutingEventHandlerDelegate(this, listener, + handler != null ? handler : new Handler(mInitializationLooper))); } } } @@ -1393,39 +1396,42 @@ public class AudioRecord implements AudioRouting * @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(); + @Override + public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { + synchronized (mRoutingChangeListeners) { + if (mRoutingChangeListeners.containsKey(listener)) { + mRoutingChangeListeners.remove(listener); + testDisableNativeRoutingCallbacksLocked(); } } } //-------------------------------------------------------------------------- - // Marshmallow (Re)Routing Info + // (Re)Routing Info //-------------------- /** - * Defines the interface by which applications can receive notifications of routing - * changes for the associated {@link AudioRecord}. + * Defines the interface by which applications can receive notifications of + * routing changes for the associated {@link AudioRecord}. + * + * @deprecated users should switch to the general purpose + * {@link AudioRouting.OnRoutingChangedListener} class instead. */ - public interface OnRoutingChangedListener { + @Deprecated + public interface OnRoutingChangedListener extends AudioRouting.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. + * 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)} - * by an app to receive (re)routing notifications. - */ - private ArrayMap - mRoutingChangeListeners = - new ArrayMap(); + @Override + default public void onRoutingChanged(AudioRouting router) { + if (router instanceof AudioRecord) { + onRoutingChanged((AudioRecord) router); + } + } + } /** * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes @@ -1435,88 +1441,28 @@ public class AudioRecord implements AudioRouting * @param handler Specifies the {@link Handler} object for the thread on which to execute * the callback. If null, the {@link Handler} associated with the main * {@link Looper} will be used. + * @deprecated users should switch to the general purpose + * {@link AudioRouting.OnRoutingChangedListener} class instead. */ @Deprecated public void addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler) { - if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { - synchronized (mRoutingChangeListeners) { - testEnableNativeRoutingCallbacks(); - mRoutingChangeListeners.put( - listener, new NativeRoutingEventHandlerDelegate(this, listener, - handler != null ? handler : new Handler(mInitializationLooper))); - } - } + addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler); } /** * Removes an {@link OnRoutingChangedListener} which has been previously added * to receive rerouting notifications. * @param listener The previously added {@link OnRoutingChangedListener} interface to remove. + * @deprecated users should switch to the general purpose + * {@link AudioRouting.OnRoutingChangedListener} class instead. */ @Deprecated public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) { - synchronized (mRoutingChangeListeners) { - if (mRoutingChangeListeners.containsKey(listener)) { - mRoutingChangeListeners.remove(listener); - testDisableNativeRoutingCallbacks(); - } - } + removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener); } /** - * >= "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 */ @@ -1524,7 +1470,7 @@ public class AudioRecord implements AudioRouting private final Handler mHandler; NativeRoutingEventHandlerDelegate(final AudioRecord record, - final OnRoutingChangedListener listener, + final AudioRouting.OnRoutingChangedListener listener, Handler handler) { // find the looper for our new event handler Looper looper; @@ -1571,26 +1517,12 @@ public class AudioRecord implements AudioRouting */ private void broadcastRoutingChange() { AudioManager.resetAudioPortGeneration(); - // Marshmallow Routing - Collection values; synchronized (mRoutingChangeListeners) { - values = mRoutingChangeListeners.values(); - } - for(NativeRoutingEventHandlerDelegate delegate : values) { - Handler handler = delegate.getHandler(); - if (handler != null) { - handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE); - } - } - // >= "N" Routing - Collection newValues; - synchronized (mNewRoutingChangeListeners) { - newValues = mNewRoutingChangeListeners.values(); - } - for(NativeNewRoutingEventHandlerDelegate delegate : newValues) { - Handler handler = delegate.getHandler(); - if (handler != null) { - handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE); + for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { + Handler handler = delegate.getHandler(); + if (handler != null) { + handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE); + } } } } @@ -1623,6 +1555,7 @@ public class AudioRecord implements AudioRouting * @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and * does not correspond to a valid audio input device. */ + @Override public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { // Do some validation.... if (deviceInfo != null && !deviceInfo.isSource()) { @@ -1643,6 +1576,7 @@ public class AudioRecord implements AudioRouting * Returns the selected input specified by {@link #setPreferredDevice}. Note that this * is not guarenteed to correspond to the actual device being used for recording. */ + @Override public AudioDeviceInfo getPreferredDevice() { synchronized (this) { return mPreferredDevice; @@ -1683,7 +1617,6 @@ public class AudioRecord implements AudioRouting * (potentially) handled in a different thread */ private class NativeEventHandler extends Handler { - private final AudioRecord mAudioRecord; NativeEventHandler(AudioRecord recorder, Looper looper) { @@ -1714,8 +1647,7 @@ public class AudioRecord implements AudioRouting break; } } - }; - + } //--------------------------------------------------------- // Java methods called from the native side diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java index 41f92d49e39f4..26fa631ac6ac7 100644 --- a/media/java/android/media/AudioRouting.java +++ b/media/java/android/media/AudioRouting.java @@ -57,7 +57,7 @@ public interface AudioRouting { * the callback. If null, the {@link Handler} associated with the main * {@link Looper} will be used. */ - public void addOnRoutingListener(OnRoutingChangedListener listener, + public void addOnRoutingChangedListener(OnRoutingChangedListener listener, Handler handler); /** @@ -66,7 +66,7 @@ public interface AudioRouting { * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface * to remove. */ - public void removeOnRoutingListener(OnRoutingChangedListener listener); + public void removeOnRoutingChangedListener(OnRoutingChangedListener listener); /** * Defines the interface by which applications can receive notifications of routing diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 621129d63f9c5..9d360db384c8c 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -40,6 +40,7 @@ import android.os.ServiceManager; import android.util.ArrayMap; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; /** @@ -1489,6 +1490,7 @@ public class AudioTrack implements AudioRouting * @deprecated Applications should use {@link #setVolume} instead, as it * more gracefully scales down to mono, and up to multi-channel content beyond stereo. */ + @Deprecated public int setStereoVolume(float leftGain, float rightGain) { if (isRestricted()) { return SUCCESS; @@ -2397,6 +2399,7 @@ public class AudioTrack implements AudioRouting * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and * does not correspond to a valid audio output device. */ + @Override public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { // Do some validation.... if (deviceInfo != null && !deviceInfo.isSink()) { @@ -2416,6 +2419,7 @@ public class AudioTrack implements AudioRouting * Returns the selected output specified by {@link #setPreferredDevice}. Note that this * is not guaranteed to correspond to the actual device being used for playback. */ + @Override public AudioDeviceInfo getPreferredDevice() { synchronized (this) { return mPreferredDevice; @@ -2427,6 +2431,7 @@ public class AudioTrack implements AudioRouting * Note: The query is only valid if the AudioTrack is currently playing. If it is not, * getRoutedDevice() will return null. */ + @Override public AudioDeviceInfo getRoutedDevice() { int deviceId = native_getRoutedDeviceId(); if (deviceId == 0) { @@ -2445,8 +2450,8 @@ public class AudioTrack implements AudioRouting /* * Call BEFORE adding a routing callback handler. */ - private void testEnableNativeRoutingCallbacks() { - if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) { + private void testEnableNativeRoutingCallbacksLocked() { + if (mRoutingChangeListeners.size() == 0) { native_enableDeviceCallback(); } } @@ -2454,24 +2459,23 @@ public class AudioTrack implements AudioRouting /* * Call AFTER removing a routing callback handler. */ - private void testDisableNativeRoutingCallbacks() { - if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) { + private void testDisableNativeRoutingCallbacksLocked() { + if (mRoutingChangeListeners.size() == 0) { native_disableDeviceCallback(); } } //-------------------------------------------------------------------------- - // >= "N" (Re)Routing Info + // (Re)Routing Info //-------------------- /** * The list of AudioRouting.OnRoutingChangedListener interfaces added (with - * {@link AudioTrack#addOnRoutingListener(AudioRouting.OnRoutingChangedListener, - * android.os.Handler)} - * by an app to receive (re)routing notifications. + * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive + * (re)routing notifications. */ - private ArrayMap - mNewRoutingChangeListeners = - new ArrayMap(); + @GuardedBy("mRoutingChangeListeners") + private ArrayMap mRoutingChangeListeners = new ArrayMap<>(); /** * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing @@ -2482,14 +2486,15 @@ public class AudioTrack implements AudioRouting * the callback. If null, the {@link Handler} associated with the main * {@link Looper} will be used. */ - public void addOnRoutingListener(AudioRouting.OnRoutingChangedListener listener, + @Override + public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, Handler handler) { - if (listener != null && !mNewRoutingChangeListeners.containsKey(listener)) { - synchronized (mNewRoutingChangeListeners) { - testEnableNativeRoutingCallbacks(); - mNewRoutingChangeListeners.put( - listener, new NativeNewRoutingEventHandlerDelegate(this, listener, - handler != null ? handler : new Handler(mInitializationLooper))); + synchronized (mRoutingChangeListeners) { + if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { + testEnableNativeRoutingCallbacksLocked(); + mRoutingChangeListeners.put( + listener, new NativeRoutingEventHandlerDelegate(this, listener, + handler != null ? handler : new Handler(mInitializationLooper))); } } } @@ -2500,39 +2505,42 @@ public class AudioTrack implements AudioRouting * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface * to remove. */ - public void removeOnRoutingListener(AudioRouting.OnRoutingChangedListener listener) { - if (mNewRoutingChangeListeners.containsKey(listener)) { - mNewRoutingChangeListeners.remove(listener); + @Override + public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { + synchronized (mRoutingChangeListeners) { + if (mRoutingChangeListeners.containsKey(listener)) { + mRoutingChangeListeners.remove(listener); + } + testDisableNativeRoutingCallbacksLocked(); } - testDisableNativeRoutingCallbacks(); } //-------------------------------------------------------------------------- - // Marshmallow (Re)Routing Info + // (Re)Routing Info //-------------------- /** - * Defines the interface by which applications can receive notifications of routing - * changes for the associated {@link AudioTrack}. + * Defines the interface by which applications can receive notifications of + * routing changes for the associated {@link AudioTrack}. + * + * @deprecated users should switch to the general purpose + * {@link AudioRouting.OnRoutingChangedListener} class instead. */ @Deprecated - public interface OnRoutingChangedListener { + public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener { /** - * Called when the routing of an AudioTrack changes from either and explicit or - * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-to - * device. + * Called when the routing of an AudioTrack changes from either and + * explicit or policy rerouting. Use {@link #getRoutedDevice()} to + * retrieve the newly routed-to device. */ - @Deprecated public void onRoutingChanged(AudioTrack audioTrack); - } - /** - * The list of AudioTrack.OnRoutingChangedListener interfaces added (with - * {@link AudioTrack#addOnRoutingChangedListener(OnRoutingChangedListener, android.os.Handler)} - * by an app to receive (re)routing notifications. - */ - private ArrayMap - mRoutingChangeListeners = - new ArrayMap(); + @Override + default public void onRoutingChanged(AudioRouting router) { + if (router instanceof AudioTrack) { + onRoutingChanged((AudioTrack) router); + } + } + } /** * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes @@ -2542,33 +2550,25 @@ public class AudioTrack implements AudioRouting * @param handler Specifies the {@link Handler} object for the thread on which to execute * the callback. If null, the {@link Handler} associated with the main * {@link Looper} will be used. + * @deprecated users should switch to the general purpose + * {@link AudioRouting.OnRoutingChangedListener} class instead. */ @Deprecated public void addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler) { - if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { - synchronized (mRoutingChangeListeners) { - testEnableNativeRoutingCallbacks(); - mRoutingChangeListeners.put( - listener, new NativeRoutingEventHandlerDelegate(this, listener, - handler != null ? handler : new Handler(mInitializationLooper))); - } - } + addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler); } /** * Removes an {@link OnRoutingChangedListener} which has been previously added * to receive rerouting notifications. * @param listener The previously added {@link OnRoutingChangedListener} interface to remove. + * @deprecated users should switch to the general purpose + * {@link AudioRouting.OnRoutingChangedListener} class instead. */ @Deprecated public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) { - synchronized (mRoutingChangeListeners) { - if (mRoutingChangeListeners.containsKey(listener)) { - mRoutingChangeListeners.remove(listener); - } - testDisableNativeRoutingCallbacks(); - } + removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener); } /** @@ -2576,27 +2576,12 @@ public class AudioTrack implements AudioRouting */ private void broadcastRoutingChange() { AudioManager.resetAudioPortGeneration(); - - // Marshmallow Routing - Collection values; synchronized (mRoutingChangeListeners) { - values = mRoutingChangeListeners.values(); - } - for(NativeRoutingEventHandlerDelegate delegate : values) { - Handler handler = delegate.getHandler(); - if (handler != null) { - handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE); - } - } - // >= "N" Routing - Collection newValues; - synchronized (mNewRoutingChangeListeners) { - newValues = mNewRoutingChangeListeners.values(); - } - for(NativeNewRoutingEventHandlerDelegate delegate : newValues) { - Handler handler = delegate.getHandler(); - if (handler != null) { - handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE); + for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { + Handler handler = delegate.getHandler(); + if (handler != null) { + handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE); + } } } } @@ -2681,7 +2666,6 @@ public class AudioTrack implements AudioRouting } /** - * Marshmallow Routing API. * Helper class to handle the forwarding of native events to the appropriate listener * (potentially) handled in a different thread */ @@ -2689,57 +2673,6 @@ public class AudioTrack implements AudioRouting private final Handler mHandler; NativeRoutingEventHandlerDelegate(final AudioTrack track, - final 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 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 AudioSystem.NATIVE_EVENT_ROUTING_CHANGE: - if (listener != null) { - listener.onRoutingChanged(track); - } - break; - default: - loge("Unknown native event type: " + msg.what); - break; - } - } - }; - } else { - mHandler = null; - } - } - - Handler getHandler() { - return mHandler; - } - } - - /** - * Marshmallow Routing API. - * 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 AudioTrack track, final AudioRouting.OnRoutingChangedListener listener, Handler handler) { // find the looper for our new event handler