From 510225b5ef52143e46079b10b1fe285b69140a77 Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Wed, 24 Jan 2018 14:27:16 -0800 Subject: [PATCH] add getMetrics() apis for AudioTrack and AudioRecord add getMetrics() method to access media.metrics for AudioTrack and AudioRecord. Includes the code paths and the sdk documentation for the keys and what they return. Moves the media metrics JNI support routines from media to core to support these audiotrack/record operations being there; still accessible to the existing operations in the media libraries. Bug: 72179020 Bug: 72178968 Test: enhanced CTS Change-Id: I3f05beba31aacb9b96854f8a774cb8f669ee1625 --- api/current.txt | 18 ++++++ core/jni/Android.bp | 2 + core/jni/android_media_AudioRecord.cpp | 36 +++++++++++ core/jni/android_media_AudioTrack.cpp | 36 +++++++++++ .../jni/android_media_MediaMetricsJNI.cpp | 0 .../jni/android_media_MediaMetricsJNI.h | 0 media/java/android/media/AudioRecord.java | 60 +++++++++++++++++++ media/java/android/media/AudioTrack.java | 60 +++++++++++++++++++ media/jni/Android.bp | 2 - 9 files changed, 212 insertions(+), 2 deletions(-) rename {media => core}/jni/android_media_MediaMetricsJNI.cpp (100%) rename {media => core}/jni/android_media_MediaMetricsJNI.h (100%) diff --git a/api/current.txt b/api/current.txt index c38690c4ba8d0..5410b9daca047 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22097,6 +22097,7 @@ package android.media { method public int getChannelConfiguration(); method public int getChannelCount(); method public android.media.AudioFormat getFormat(); + method public android.os.PersistableBundle getMetrics(); method public static int getMinBufferSize(int, int, int); method public int getNotificationMarkerPosition(); method public int getPositionNotificationPeriod(); @@ -22145,6 +22146,14 @@ package android.media { method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException; } + public static final class AudioRecord.MetricsConstants { + field public static final java.lang.String CHANNELS = "android.media.audiorecord.channels"; + field public static final java.lang.String ENCODING = "android.media.audiorecord.encoding"; + field public static final java.lang.String LATENCY = "android.media.audiorecord.latency"; + field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate"; + field public static final java.lang.String SOURCE = "android.media.audiorecord.source"; + } + public static abstract interface AudioRecord.OnRecordPositionUpdateListener { method public abstract void onMarkerReached(android.media.AudioRecord); method public abstract void onPeriodicNotification(android.media.AudioRecord); @@ -22204,6 +22213,7 @@ package android.media { method public int getChannelCount(); method public android.media.AudioFormat getFormat(); method public static float getMaxVolume(); + method public android.os.PersistableBundle getMetrics(); method public static int getMinBufferSize(int, int, int); method public static float getMinVolume(); method protected deprecated int getNativeFrameCount(); @@ -22284,6 +22294,14 @@ package android.media { method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException; } + public static final class AudioTrack.MetricsConstants { + field public static final java.lang.String CHANNELMASK = "android.media.audiorecord.channelmask"; + field public static final java.lang.String CONTENTTYPE = "android.media.audiotrack.type"; + field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate"; + field public static final java.lang.String STREAMTYPE = "android.media.audiotrack.streamtype"; + field public static final java.lang.String USAGE = "android.media.audiotrack.usage"; + } + public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener { method public abstract void onMarkerReached(android.media.AudioTrack); method public abstract void onPeriodicNotification(android.media.AudioTrack); diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 102ff95e6d323..5751fc99a4849 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -163,6 +163,7 @@ cc_library_shared { "android_media_AudioTrack.cpp", "android_media_DeviceCallback.cpp", "android_media_JetPlayer.cpp", + "android_media_MediaMetricsJNI.cpp", "android_media_RemoteDisplay.cpp", "android_media_ToneGenerator.cpp", "android_hardware_Camera.cpp", @@ -261,6 +262,7 @@ cc_library_shared { "libselinux", "libicuuc", "libmedia", + "libmediametrics", "libaudioclient", "libjpeg", "libusbhost", diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index e4da3c6a6ac8d..ebd16c7084ac5 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -31,6 +31,7 @@ #include "android_media_AudioFormat.h" #include "android_media_AudioErrors.h" #include "android_media_DeviceCallback.h" +#include "android_media_MediaMetricsJNI.h" // ---------------------------------------------------------------------------- @@ -750,6 +751,39 @@ static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz, return status; } +// ---------------------------------------------------------------------------- +static jobject +android_media_AudioRecord_native_getMetrics(JNIEnv *env, jobject thiz) +{ + ALOGV("android_media_AudioRecord_native_getMetrics"); + + sp lpRecord = getAudioRecord(env, thiz); + + if (lpRecord == NULL) { + ALOGE("Unable to retrieve AudioRecord pointer for getMetrics()"); + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return (jobject) NULL; + } + + // get what we have for the metrics from the record session + MediaAnalyticsItem *item = NULL; + + status_t err = lpRecord->getMetrics(item); + if (err != OK) { + ALOGE("getMetrics failed"); + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return (jobject) NULL; + } + + jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */); + + // housekeeping + delete item; + item = NULL; + + return mybundle; +} + // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { @@ -781,6 +815,8 @@ static const JNINativeMethod gMethods[] = { "()I", (void *)android_media_AudioRecord_get_pos_update_period}, {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioRecord_get_min_buff_size}, + {"native_getMetrics", "()Landroid/os/PersistableBundle;", + (void *)android_media_AudioRecord_native_getMetrics}, {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice}, {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId}, {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 11011b1d7c164..afbc579136880 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -34,6 +34,7 @@ #include "android_media_AudioFormat.h" #include "android_media_AudioErrors.h" +#include "android_media_MediaMetricsJNI.h" #include "android_media_PlaybackParams.h" #include "android_media_DeviceCallback.h" #include "android_media_VolumeShaper.h" @@ -1011,6 +1012,39 @@ static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, j return (jint) nativeToJavaStatus(status); } +// ---------------------------------------------------------------------------- +static jobject +android_media_AudioTrack_native_getMetrics(JNIEnv *env, jobject thiz) +{ + ALOGD("android_media_AudioTrack_native_getMetrics"); + + sp lpTrack = getAudioTrack(env, thiz); + + if (lpTrack == NULL) { + ALOGE("Unable to retrieve AudioTrack pointer for getMetrics()"); + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return (jobject) NULL; + } + + // get what we have for the metrics from the track + MediaAnalyticsItem *item = NULL; + + status_t err = lpTrack->getMetrics(item); + if (err != OK) { + ALOGE("getMetrics failed"); + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return (jobject) NULL; + } + + jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */); + + // housekeeping + delete item; + item = NULL; + + return mybundle; +} + // ---------------------------------------------------------------------------- static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz, @@ -1275,6 +1309,8 @@ static const JNINativeMethod gMethods[] = { {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count}, {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags}, {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp}, + {"native_getMetrics", "()Landroid/os/PersistableBundle;", + (void *)android_media_AudioTrack_native_getMetrics}, {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop}, {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload}, {"native_get_output_sample_rate", diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/core/jni/android_media_MediaMetricsJNI.cpp similarity index 100% rename from media/jni/android_media_MediaMetricsJNI.cpp rename to core/jni/android_media_MediaMetricsJNI.cpp diff --git a/media/jni/android_media_MediaMetricsJNI.h b/core/jni/android_media_MediaMetricsJNI.h similarity index 100% rename from media/jni/android_media_MediaMetricsJNI.h rename to core/jni/android_media_MediaMetricsJNI.h diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 27784e96d9f9d..eb6e83065fe9b 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -32,6 +32,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ServiceManager; import android.util.ArrayMap; @@ -1314,6 +1315,23 @@ public class AudioRecord implements AudioRouting return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING); } + /** + * Return Metrics data about the current AudioTrack instance. + * + * @return a {@link PersistableBundle} containing the set of attributes and values + * available for the media being handled by this instance of AudioRecord + * The attributes are descibed in {@link MetricsConstants}. + * + * Additional vendor-specific fields may also be present in + * the return value. + */ + public PersistableBundle getMetrics() { + PersistableBundle bundle = native_getMetrics(); + return bundle; + } + + private native PersistableBundle native_getMetrics(); + //-------------------------------------------------------------------------- // Initialization / configuration //-------------------- @@ -1739,4 +1757,46 @@ public class AudioRecord implements AudioRouting private static void loge(String msg) { Log.e(TAG, msg); } + + public static final class MetricsConstants + { + private MetricsConstants() {} + + /** + * Key to extract the output format being recorded + * from the {@link AudioRecord#getMetrics} return value. + * The value is a String. + */ + public static final String ENCODING = "android.media.audiorecord.encoding"; + + /** + * Key to extract the Source Type for this track + * from the {@link AudioRecord#getMetrics} return value. + * The value is a String. + */ + public static final String SOURCE = "android.media.audiorecord.source"; + + /** + * Key to extract the estimated latency through the recording pipeline + * from the {@link AudioRecord#getMetrics} return value. + * This is in units of milliseconds. + * The value is an integer. + */ + public static final String LATENCY = "android.media.audiorecord.latency"; + + /** + * Key to extract the sink sample rate for this record track in Hz + * from the {@link AudioRecord#getMetrics} return value. + * The value is an integer. + */ + public static final String SAMPLERATE = "android.media.audiorecord.samplerate"; + + /** + * Key to extract the number of channels being recorded in this record track + * from the {@link AudioRecord#getMetrics} return value. + * The value is an integer. + */ + public static final String CHANNELS = "android.media.audiorecord.channels"; + + } } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 5928d03dc4a10..4e9ce8e23e9c8 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -36,6 +36,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -1718,6 +1719,23 @@ public class AudioTrack extends PlayerBase return ret; } + /** + * Return Metrics data about the current AudioTrack instance. + * + * @return a {@link PersistableBundle} containing the set of attributes and values + * available for the media being handled by this instance of AudioTrack + * The attributes are descibed in {@link MetricsConstants}. + * + * Additional vendor-specific fields may also be present in + * the return value. + */ + public PersistableBundle getMetrics() { + PersistableBundle bundle = native_getMetrics(); + return bundle; + } + + private native PersistableBundle native_getMetrics(); + //-------------------------------------------------------------------------- // Initialization / configuration //-------------------- @@ -3239,4 +3257,46 @@ public class AudioTrack extends PlayerBase private static void loge(String msg) { Log.e(TAG, msg); } + + public final static class MetricsConstants + { + private MetricsConstants() {} + + /** + * Key to extract the Stream Type for this track + * from the {@link AudioTrack#getMetrics} return value. + * The value is a String. + */ + public static final String STREAMTYPE = "android.media.audiotrack.streamtype"; + + /** + * Key to extract the Content Type for this track + * from the {@link AudioTrack#getMetrics} return value. + * The value is a String. + */ + public static final String CONTENTTYPE = "android.media.audiotrack.type"; + + /** + * Key to extract the Content Type for this track + * from the {@link AudioTrack#getMetrics} return value. + * The value is a String. + */ + public static final String USAGE = "android.media.audiotrack.usage"; + + /** + * Key to extract the sample rate for this track in Hz + * from the {@link AudioTrack#getMetrics} return value. + * The value is an integer. + */ + public static final String SAMPLERATE = "android.media.audiorecord.samplerate"; + + /** + * Key to extract the channel mask information for this track + * from the {@link AudioTrack#getMetrics} return value. + * + * The value is a Long integer. + */ + public static final String CHANNELMASK = "android.media.audiorecord.channelmask"; + + } } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 4b4a255644c38..74f3acad74fdb 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -12,7 +12,6 @@ cc_library_shared { "android_media_MediaDrm.cpp", "android_media_MediaExtractor.cpp", "android_media_MediaHTTPConnection.cpp", - "android_media_MediaMetricsJNI.cpp", "android_media_MediaMetadataRetriever.cpp", "android_media_MediaMuxer.cpp", "android_media_MediaPlayer.cpp", @@ -93,7 +92,6 @@ cc_library_shared { "android_media_MediaCrypto.cpp", "android_media_Media2DataSource.cpp", "android_media_MediaDrm.cpp", - "android_media_MediaMetricsJNI.cpp", "android_media_MediaPlayer2.cpp", "android_media_SyncParams.cpp", ],