diff options
| author | 2018-12-21 02:25:45 +0000 | |
|---|---|---|
| committer | 2018-12-21 02:25:45 +0000 | |
| commit | 0a9b04a6faf4501cb9d4ccf877f66aae85992df8 (patch) | |
| tree | 7432559f747fb99402736b7c8b332921c9adb083 | |
| parent | 243ca1b71f8e781484629e85d63ce52086594e08 (diff) | |
| parent | 333dfad3bf51340e93a00e3fe440641b96414f8a (diff) | |
Merge "Add AudioRecordingConfiguration changed callback"
| -rw-r--r-- | api/current.txt | 16 | ||||
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | media/java/android/media/AudioRecord.java | 55 | ||||
| -rw-r--r-- | media/java/android/media/AudioRecordingMonitor.java | 56 | ||||
| -rw-r--r-- | media/java/android/media/AudioRecordingMonitorClient.java | 28 | ||||
| -rw-r--r-- | media/java/android/media/AudioRecordingMonitorImpl.java | 250 | ||||
| -rw-r--r-- | media/java/android/media/MediaRecorder.java | 61 | ||||
| -rw-r--r-- | media/jni/android_media_MediaRecorder.cpp | 15 |
8 files changed, 477 insertions, 6 deletions
diff --git a/api/current.txt b/api/current.txt index d881857b3c0f..f9b566087a8b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23379,12 +23379,13 @@ package android.media { method public android.media.AudioPresentation.Builder setProgramId(int); } - public class AudioRecord implements android.media.AudioRouting { + public class AudioRecord implements android.media.AudioRecordingMonitor 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 protected void finalize(); method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException; + method public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration(); method public int getAudioFormat(); method public int getAudioSessionId(); method public int getAudioSource(); @@ -23409,6 +23410,7 @@ package android.media { method public int read(float[], int, int, int); method public int read(java.nio.ByteBuffer, int); method public int read(java.nio.ByteBuffer, int, int); + method public void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback); method public void release(); method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener); @@ -23420,6 +23422,7 @@ package android.media { method public void startRecording() throws java.lang.IllegalStateException; method public void startRecording(android.media.MediaSyncEvent) throws java.lang.IllegalStateException; method public void stop() throws java.lang.IllegalStateException; + method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback); field public static final int ERROR = -1; // 0xffffffff field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa @@ -23474,6 +23477,12 @@ package android.media { field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR; } + public abstract interface AudioRecordingMonitor { + method public abstract android.media.AudioRecordingConfiguration getActiveRecordingConfiguration(); + method public abstract void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback); + method public abstract void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback); + } + public abstract interface AudioRouting { method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public abstract android.media.AudioDeviceInfo getPreferredDevice(); @@ -25475,11 +25484,12 @@ package android.media { field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1 } - public class MediaRecorder implements android.media.AudioRouting { + public class MediaRecorder implements android.media.AudioRecordingMonitor android.media.AudioRouting { ctor public MediaRecorder(); method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method protected void finalize(); method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException; + method public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration(); method public static final int getAudioSourceMax(); method public int getMaxAmplitude() throws java.lang.IllegalStateException; method public android.os.PersistableBundle getMetrics(); @@ -25488,6 +25498,7 @@ package android.media { method public android.view.Surface getSurface(); method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; + method public void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback); method public void release(); method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public void reset(); @@ -25523,6 +25534,7 @@ package android.media { method public void setVideoSource(int) throws java.lang.IllegalStateException; method public void start() throws java.lang.IllegalStateException; method public void stop() throws java.lang.IllegalStateException; + method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback); field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64 field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1 field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320 diff --git a/api/system-current.txt b/api/system-current.txt index 565623c5e0d8..3aa7cc7a1bdb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2953,7 +2953,7 @@ package android.media { field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff } - public class AudioRecord implements android.media.AudioRouting { + public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting { ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException; } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 4b2353c992f2..33f81f1db69c 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -16,8 +16,10 @@ package android.media; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; @@ -43,6 +45,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.Executor; /** * The AudioRecord class manages the audio resources for Java applications @@ -58,7 +61,7 @@ import java.util.List; * 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 implements AudioRouting +public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRecordingMonitorClient { //--------------------------------------------------------- // Constants @@ -1654,6 +1657,56 @@ public class AudioRecord implements AudioRouting return activeMicrophones; } + + //-------------------------------------------------------------------------- + // Implementation of AudioRecordingMonitor interface + //-------------------- + + AudioRecordingMonitorImpl mRecordingInfoImpl = + new AudioRecordingMonitorImpl((AudioRecordingMonitorClient) this); + + /** + * Register a callback to be notified of audio capture changes via a + * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path + * configuration changes (pre-processing, format, sampling rate...) or capture is + * silenced/unsilenced by the system. + * @param executor {@link Executor} to handle the callbacks. + * @param cb non-null callback to register + */ + public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull AudioManager.AudioRecordingCallback cb) { + mRecordingInfoImpl.registerAudioRecordingCallback(executor, cb); + } + + /** + * Unregister an audio recording callback previously registered with + * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}. + * @param cb non-null callback to unregister + */ + public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) { + mRecordingInfoImpl.unregisterAudioRecordingCallback(cb); + } + + /** + * Returns the current active audio recording for this audio recorder. + * @return a valid {@link AudioRecordingConfiguration} if this recorder is active + * or null otherwise. + * @see AudioRecordingConfiguration + */ + public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() { + return mRecordingInfoImpl.getActiveRecordingConfiguration(); + } + + //--------------------------------------------------------- + // Implementation of AudioRecordingMonitorClient interface + //-------------------- + /** + * @hide + */ + public int getPortId() { + return native_getPortId(); + } + //--------------------------------------------------------- // Interface definitions //-------------------- diff --git a/media/java/android/media/AudioRecordingMonitor.java b/media/java/android/media/AudioRecordingMonitor.java new file mode 100644 index 000000000000..e2605d074c86 --- /dev/null +++ b/media/java/android/media/AudioRecordingMonitor.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 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; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.util.concurrent.Executor; + +/** + * AudioRecordingMonitor defines an interface implemented by {@link AudioRecord} and + * {@link MediaRecorder} allowing applications to install a callback and be notified of changes + * in the capture path while recoding is active. + */ +public interface AudioRecordingMonitor { + /** + * Register a callback to be notified of audio capture changes via a + * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path + * configuration changes (pre-processing, format, sampling rate...) or capture is + * silenced/unsilenced by the system. + * @param executor {@link Executor} to handle the callbacks. + * @param cb non-null callback to register + */ + void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull AudioManager.AudioRecordingCallback cb); + + /** + * Unregister an audio recording callback previously registered with + * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}. + * @param cb non-null callback to unregister + */ + void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb); + + /** + * Returns the current active audio recording for this audio recorder. + * @return a valid {@link AudioRecordingConfiguration} if this recorder is active + * or null otherwise. + * @see AudioRecordingConfiguration + */ + @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration(); +} diff --git a/media/java/android/media/AudioRecordingMonitorClient.java b/media/java/android/media/AudioRecordingMonitorClient.java new file mode 100644 index 000000000000..7578d9b9a5fd --- /dev/null +++ b/media/java/android/media/AudioRecordingMonitorClient.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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; + +/** + * Interface implemented by classes using { @link AudioRecordingMonitor} interface. + * @hide + */ +public interface AudioRecordingMonitorClient { + /** + * @return the unique port ID allocated by audio framework to this recorder + */ + int getPortId(); +} diff --git a/media/java/android/media/AudioRecordingMonitorImpl.java b/media/java/android/media/AudioRecordingMonitorImpl.java new file mode 100644 index 000000000000..c2cd4bc0b7eb --- /dev/null +++ b/media/java/android/media/AudioRecordingMonitorImpl.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2018 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; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Implementation of AudioRecordingMonitor interface. + * @hide + */ +public class AudioRecordingMonitorImpl implements AudioRecordingMonitor { + + private static final String TAG = "android.media.AudioRecordingMonitor"; + + private static IAudioService sService; //lazy initialization, use getService() + + private final AudioRecordingMonitorClient mClient; + + AudioRecordingMonitorImpl(@NonNull AudioRecordingMonitorClient client) { + mClient = client; + } + + /** + * Register a callback to be notified of audio capture changes via a + * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path + * configuration changes (pre-processing, format, sampling rate...) or capture is + * silenced/unsilenced by the system. + * @param executor {@link Executor} to handle the callbacks. + * @param cb non-null callback to register + */ + public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull AudioManager.AudioRecordingCallback cb) { + if (cb == null) { + throw new IllegalArgumentException("Illegal null AudioRecordingCallback"); + } + if (executor == null) { + throw new IllegalArgumentException("Illegal null Executor"); + } + synchronized (mRecordCallbackLock) { + // check if eventCallback already in list + for (AudioRecordingCallbackInfo arci : mRecordCallbackList) { + if (arci.mCb == cb) { + throw new IllegalArgumentException( + "AudioRecordingCallback already registered"); + } + } + beginRecordingCallbackHandling(); + mRecordCallbackList.add(new AudioRecordingCallbackInfo(executor, cb)); + } + } + + /** + * Unregister an audio recording callback previously registered with + * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}. + * @param cb non-null callback to unregister + */ + public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) { + if (cb == null) { + throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); + } + + synchronized (mRecordCallbackLock) { + for (AudioRecordingCallbackInfo arci : mRecordCallbackList) { + if (arci.mCb == cb) { + // ok to remove while iterating over list as we exit iteration + mRecordCallbackList.remove(arci); + if (mRecordCallbackList.size() == 0) { + endRecordingCallbackHandling(); + } + return; + } + } + throw new IllegalArgumentException("AudioRecordingCallback was not registered"); + } + } + + /** + * Returns the current active audio recording for this audio recorder. + * @return a valid {@link AudioRecordingConfiguration} if this recorder is active + * or null otherwise. + * @see AudioRecordingConfiguration + */ + public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() { + final IAudioService service = getService(); + try { + List<AudioRecordingConfiguration> configs = service.getActiveRecordingConfigurations(); + return getMyConfig(configs); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private static class AudioRecordingCallbackInfo { + final AudioManager.AudioRecordingCallback mCb; + final Executor mExecutor; + AudioRecordingCallbackInfo(Executor e, AudioManager.AudioRecordingCallback cb) { + mExecutor = e; + mCb = cb; + } + } + + private static final int MSG_RECORDING_CONFIG_CHANGE = 1; + + private final Object mRecordCallbackLock = new Object(); + @GuardedBy("mRecordCallbackLock") + @NonNull private LinkedList<AudioRecordingCallbackInfo> mRecordCallbackList = + new LinkedList<AudioRecordingCallbackInfo>(); + @GuardedBy("mRecordCallbackLock") + private @Nullable HandlerThread mRecordingCallbackHandlerThread; + @GuardedBy("mRecordCallbackLock") + private @Nullable volatile Handler mRecordingCallbackHandler; + + @GuardedBy("mRecordCallbackLock") + private final IRecordingConfigDispatcher mRecordingCallback = + new IRecordingConfigDispatcher.Stub() { + @Override + public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) { + AudioRecordingConfiguration config = getMyConfig(configs); + if (config != null) { + synchronized (mRecordCallbackLock) { + if (mRecordingCallbackHandler != null) { + final Message m = mRecordingCallbackHandler.obtainMessage( + MSG_RECORDING_CONFIG_CHANGE/*what*/, config /*obj*/); + mRecordingCallbackHandler.sendMessage(m); + } + } + } + } + }; + + @GuardedBy("mRecordCallbackLock") + private void beginRecordingCallbackHandling() { + if (mRecordingCallbackHandlerThread == null) { + mRecordingCallbackHandlerThread = new HandlerThread(TAG + ".RecordingCallback"); + mRecordingCallbackHandlerThread.start(); + final Looper looper = mRecordingCallbackHandlerThread.getLooper(); + if (looper != null) { + mRecordingCallbackHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_RECORDING_CONFIG_CHANGE: { + if (msg.obj == null) { + return; + } + ArrayList<AudioRecordingConfiguration> configs = + new ArrayList<AudioRecordingConfiguration>(); + configs.add((AudioRecordingConfiguration) msg.obj); + + final LinkedList<AudioRecordingCallbackInfo> cbInfoList; + synchronized (mRecordCallbackLock) { + if (mRecordCallbackList.size() == 0) { + return; + } + cbInfoList = new LinkedList<AudioRecordingCallbackInfo>( + mRecordCallbackList); + } + + final long identity = Binder.clearCallingIdentity(); + try { + for (AudioRecordingCallbackInfo cbi : cbInfoList) { + cbi.mExecutor.execute(() -> + cbi.mCb.onRecordingConfigChanged(configs)); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } break; + default: + Log.e(TAG, "Unknown event " + msg.what); + break; + } + } + }; + final IAudioService service = getService(); + try { + service.registerRecordingCallback(mRecordingCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + + @GuardedBy("mRecordCallbackLock") + private void endRecordingCallbackHandling() { + if (mRecordingCallbackHandlerThread != null) { + final IAudioService service = getService(); + try { + service.unregisterRecordingCallback(mRecordingCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mRecordingCallbackHandlerThread.quit(); + mRecordingCallbackHandlerThread = null; + } + } + + AudioRecordingConfiguration getMyConfig(List<AudioRecordingConfiguration> configs) { + int portId = mClient.getPortId(); + for (AudioRecordingConfiguration config : configs) { + if (config.getClientPortId() == portId) { + return config; + } + } + return null; + } + + private static IAudioService getService() { + if (sService != null) { + return sService; + } + IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); + sService = IAudioService.Stub.asInterface(b); + return sService; + } +} diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 8ced021b1025..1cdc29102758 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -16,7 +16,9 @@ package android.media; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; @@ -40,6 +42,8 @@ import java.io.RandomAccessFile; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; + /** * Used to record audio and video. The recording control is based on a @@ -83,7 +87,9 @@ import java.util.List; * <a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a> developer guide.</p> * </div> */ -public class MediaRecorder implements AudioRouting +public class MediaRecorder implements AudioRouting, + AudioRecordingMonitor, + AudioRecordingMonitorClient { static { System.loadLibrary("media_jni"); @@ -304,7 +310,7 @@ public class MediaRecorder implements AudioRouting /** * Audio source for preemptible, low-priority software hotword detection - * It presents the same gain and pre processing tuning as {@link #VOICE_RECOGNITION}. + * It presents the same gain and pre-processing tuning as {@link #VOICE_RECOGNITION}. * <p> * An application should use this audio source when it wishes to do * always-on software hotword detection, while gracefully giving in to any other application @@ -1471,6 +1477,57 @@ public class MediaRecorder implements AudioRouting private native final int native_getActiveMicrophones( ArrayList<MicrophoneInfo> activeMicrophones); + //-------------------------------------------------------------------------- + // Implementation of AudioRecordingMonitor interface + //-------------------- + + AudioRecordingMonitorImpl mRecordingInfoImpl = + new AudioRecordingMonitorImpl((AudioRecordingMonitorClient) this); + + /** + * Register a callback to be notified of audio capture changes via a + * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path + * configuration changes (pre-processing, format, sampling rate...) or capture is + * silenced/unsilenced by the system. + * @param executor {@link Executor} to handle the callbacks. + * @param cb non-null callback to register + */ + public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull AudioManager.AudioRecordingCallback cb) { + mRecordingInfoImpl.registerAudioRecordingCallback(executor, cb); + } + + /** + * Unregister an audio recording callback previously registered with + * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}. + * @param cb non-null callback to unregister + */ + public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) { + mRecordingInfoImpl.unregisterAudioRecordingCallback(cb); + } + + /** + * Returns the current active audio recording for this audio recorder. + * @return a valid {@link AudioRecordingConfiguration} if this recorder is active + * or null otherwise. + * @see AudioRecordingConfiguration + */ + public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() { + return mRecordingInfoImpl.getActiveRecordingConfiguration(); + } + + //--------------------------------------------------------- + // Implementation of AudioRecordingMonitorClient interface + //-------------------- + /** + * @hide + */ + public int getPortId() { + return native_getPortId(); + } + + private native int native_getPortId(); + /** * Called from native code when an interesting event happens. This method * just uses the EventHandler system to post the event back to the main app thread. diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index b3a8b21147c1..ca30f32ea438 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -763,6 +763,20 @@ android_media_MediaRecord_getActiveMicrophones(JNIEnv *env, } return jStatus; } + +static jint android_media_MediaRecord_getPortId(JNIEnv *env, jobject thiz) { + sp<MediaRecorder> mr = getMediaRecorder(env, thiz); + if (mr == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return (jint)AUDIO_PORT_HANDLE_NONE; + } + + audio_port_handle_t portId; + process_media_recorder_call(env, mr->getPortId(&portId), + "java/lang/RuntimeException", "getPortId failed."); + return (jint)portId; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { @@ -801,6 +815,7 @@ static const JNINativeMethod gMethods[] = { {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaRecorder_enableDeviceCallback}, {"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones}, + {"native_getPortId", "()I", (void *)android_media_MediaRecord_getPortId}, }; // This function only registers the native methods, and is called from |