Merge "Convert IResourceManagerService to stable AIDL"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index cc43b61..defc94f 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -3,6 +3,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
stagefright.cpp \
jpeg.cpp \
SineSource.cpp
@@ -10,7 +11,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmedia_codeclist libutils libbinder \
libstagefright_foundation libjpeg libui libgui libcutils liblog \
- libhidlbase libdatasource \
+ libhidlbase libdatasource libaudioclient \
android.hardware.media.omx@1.0 \
LOCAL_C_INCLUDES:= \
@@ -31,12 +32,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
record.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation libdatasource
+ libstagefright_foundation libdatasource libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/camera/include \
@@ -57,12 +59,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
+ AudioPlayer.cpp \
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -83,12 +85,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/media/libstagefright/AudioPlayer.cpp b/cmds/stagefright/AudioPlayer.cpp
similarity index 99%
rename from media/libstagefright/AudioPlayer.cpp
rename to cmds/stagefright/AudioPlayer.cpp
index 199b57b..208713d 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/cmds/stagefright/AudioPlayer.cpp
@@ -28,12 +28,13 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include "AudioPlayer.h"
+
namespace android {
AudioPlayer::AudioPlayer(
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/cmds/stagefright/AudioPlayer.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/AudioPlayer.h
rename to cmds/stagefright/AudioPlayer.h
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index d4f2e8d..bd274d8 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -29,11 +29,11 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AMRWriter.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/SimpleDecodingSource.h>
+#include "AudioPlayer.h"
#include "SineSource.h"
using namespace android;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 498237d..37091c4 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -21,7 +21,6 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -33,6 +32,8 @@
#include <media/stagefright/SimpleDecodingSource.h>
#include <media/MediaPlayerInterface.h>
+#include "AudioPlayer.h"
+
using namespace android;
static const int32_t kAudioBitRate = 12200;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index a63b9b9..01a178e 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "SineSource.h"
-
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -25,8 +23,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 58e3f2c..509d32f 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -40,7 +40,6 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
@@ -67,6 +66,8 @@
#include <android/hardware/media/omx/1.0/IOmx.h>
+#include "AudioPlayer.h"
+
using namespace android;
static long gNumRepetitions;
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index cac90ea..e929d08 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -923,9 +923,8 @@
status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
Mutex::Autolock autoLock(mLock);
- EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
-
INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
DrmSessionManager::Instance()->useSession(sessionId);
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index 3970583..e830e56 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -2,6 +2,16 @@
name: "libaudiofoundation_headers",
vendor_available: true,
export_include_dirs: ["include"],
+ header_libs: [
+ "libaudio_system_headers",
+ "libaudioclient_headers",
+ "libmedia_headers",
+ ],
+ export_header_lib_headers: [
+ "libaudio_system_headers",
+ "libaudioclient_headers",
+ "libmedia_headers",
+ ],
}
cc_library {
@@ -26,12 +36,12 @@
],
header_libs: [
- "libaudio_system_headers",
- "libaudioclient_headers",
"libaudiofoundation_headers",
],
- export_header_lib_headers: ["libaudiofoundation_headers"],
+ export_header_lib_headers: [
+ "libaudiofoundation_headers",
+ ],
cflags: [
"-Werror",
diff --git a/media/libaudiofoundation/TEST_MAPPING b/media/libaudiofoundation/TEST_MAPPING
new file mode 100644
index 0000000..f6d249a
--- /dev/null
+++ b/media/libaudiofoundation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "audiofoundation_parcelable_test"
+ }
+ ]
+}
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
new file mode 100644
index 0000000..f258b14
--- /dev/null
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+ name: "audiofoundation_parcelable_test",
+
+ shared_libs: [
+ "libaudiofoundation",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libaudio_system_headers",
+ ],
+
+ srcs: [
+ "audiofoundation_parcelable_test.cpp",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
new file mode 100644
index 0000000..5baa072
--- /dev/null
+++ b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define LOG_TAG "audiofoundation_parcelable_test"
+
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <media/AudioProfile.h>
+#include <media/DeviceDescriptorBase.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+namespace android {
+
+static const audio_port_config TEST_AUDIO_PORT_CONFIG = {
+ .id = 0,
+ .role = AUDIO_PORT_ROLE_SINK,
+ .type = AUDIO_PORT_TYPE_DEVICE,
+ .config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE | AUDIO_PORT_CONFIG_CHANNEL_MASK |
+ AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_GAIN,
+ .sample_rate = 48000,
+ .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+ .format = AUDIO_FORMAT_PCM_16_BIT,
+ .gain = {
+ .index = 0,
+ .mode = AUDIO_GAIN_MODE_JOINT,
+ .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+ }
+};
+
+class AudioPortConfigTestStub : public AudioPortConfig {
+public:
+ sp<AudioPort> getAudioPort() const override { return nullptr; }
+};
+
+AudioGains getAudioGainsForTest() {
+ AudioGains audioGains;
+ sp<AudioGain> audioGain = new AudioGain(0 /*index*/, false /*useInChannelMask*/);
+ audioGain->setMode(AUDIO_GAIN_MODE_JOINT);
+ audioGain->setChannelMask(AUDIO_CHANNEL_OUT_STEREO);
+ audioGain->setMinValueInMb(-3200);
+ audioGain->setMaxValueInMb(600);
+ audioGain->setDefaultValueInMb(0);
+ audioGain->setStepValueInMb(100);
+ audioGain->setMinRampInMs(100);
+ audioGain->setMaxRampInMs(500);
+ audioGains.push_back(audioGain);
+ return audioGains;
+}
+
+AudioProfileVector getAudioProfileVectorForTest() {
+ AudioProfileVector audioProfiles;
+ sp<AudioProfile> audioProfile = AudioProfile::createFullDynamic();
+ audioProfile->setChannels({AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO});
+ audioProfile->setSampleRates({48000});
+ audioProfiles.add(audioProfile);
+ return audioProfiles;
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioGain) {
+ Parcel data;
+ AudioGains audioGains = getAudioGainsForTest();
+
+ ASSERT_EQ(data.writeParcelable(audioGains), NO_ERROR);
+ data.setDataPosition(0);
+ AudioGains audioGainsFromParcel;
+ ASSERT_EQ(data.readParcelable(&audioGainsFromParcel), NO_ERROR);
+ ASSERT_TRUE(audioGainsFromParcel.equals(audioGains));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioProfileVector) {
+ Parcel data;
+ AudioProfileVector audioProfiles = getAudioProfileVectorForTest();
+
+ ASSERT_EQ(data.writeParcelable(audioProfiles), NO_ERROR);
+ data.setDataPosition(0);
+ AudioProfileVector audioProfilesFromParcel;
+ ASSERT_EQ(data.readParcelable(&audioProfilesFromParcel), NO_ERROR);
+ ASSERT_TRUE(audioProfilesFromParcel.equals(audioProfiles));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPort) {
+ Parcel data;
+ sp<AudioPort> audioPort = new AudioPort(
+ "AudioPortName", AUDIO_PORT_TYPE_DEVICE, AUDIO_PORT_ROLE_SINK);
+ audioPort->setGains(getAudioGainsForTest());
+ audioPort->setAudioProfiles(getAudioProfileVectorForTest());
+
+ ASSERT_EQ(data.writeParcelable(*audioPort), NO_ERROR);
+ data.setDataPosition(0);
+ sp<AudioPort> audioPortFromParcel = new AudioPort(
+ "", AUDIO_PORT_TYPE_NONE, AUDIO_PORT_ROLE_NONE);
+ ASSERT_EQ(data.readParcelable(audioPortFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(audioPortFromParcel->equals(audioPort));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPortConfig) {
+ Parcel data;
+ sp<AudioPortConfig> audioPortConfig = new AudioPortConfigTestStub();
+ audioPortConfig->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+
+ ASSERT_EQ(data.writeParcelable(*audioPortConfig), NO_ERROR);
+ data.setDataPosition(0);
+ sp<AudioPortConfig> audioPortConfigFromParcel = new AudioPortConfigTestStub();
+ ASSERT_EQ(data.readParcelable(audioPortConfigFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(audioPortConfigFromParcel->equals(audioPortConfig));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingDeviceDescriptorBase) {
+ Parcel data;
+ sp<DeviceDescriptorBase> desc = new DeviceDescriptorBase(AUDIO_DEVICE_OUT_SPEAKER);
+ desc->setGains(getAudioGainsForTest());
+ desc->setAudioProfiles(getAudioProfileVectorForTest());
+ desc->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+ desc->setAddress("DeviceDescriptorBaseTestAddress");
+
+ ASSERT_EQ(data.writeParcelable(*desc), NO_ERROR);
+ data.setDataPosition(0);
+ sp<DeviceDescriptorBase> descFromParcel = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+ ASSERT_EQ(data.readParcelable(descFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(descFromParcel->equals(desc));
+}
+
+} // namespace android
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index f2fb768..806e277 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -127,7 +127,6 @@
"ACodecBufferChannel.cpp",
"AHierarchicalStateMachine.cpp",
"AMRWriter.cpp",
- "AudioPlayer.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
"CallbackDataSource.cpp",
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
index 831944b..91b03f1 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/Android.bp
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -43,4 +43,8 @@
srcs: ["src/main/**/*.java"],
sdk_version: "system_current",
+
+ static_libs: [
+ "androidx.test.core",
+ ],
}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
index b6ac7b5..24dbccc 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
+++ b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
@@ -1,3 +1,4 @@
<resources>
<string name="input_file_path">/data/local/tmp/MediaBenchmark/res/</string>
-</resources>
\ No newline at end of file
+ <string name="output_file_path">/data/local/tmp/MediaBenchmark/output/</string>
+</resources>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
new file mode 100644
index 0000000..be2633d
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 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 com.android.media.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Extractor;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class DecoderTest {
+ private static final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+ private static final String TAG = "DecoderTest";
+ private static final long PER_TEST_TIMEOUT_MS = 60000;
+ private static final boolean DEBUG = false;
+ private static final boolean WRITE_OUTPUT = false;
+ private String mInputFile;
+ private boolean mAsyncMode;
+
+ public DecoderTest(String inputFile, boolean asyncMode) {
+ this.mInputFile = inputFile;
+ this.mAsyncMode = asyncMode;
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> input() {
+ return Arrays.asList(new Object[][]{
+ //Audio Sync Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", false},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", false},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", false},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", false},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", false},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", false},
+ // Audio Async Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", true},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", true},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", true},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", true},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", true},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", true},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", true},
+ // Video Sync Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", false},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", false},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", false},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", false},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", false},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", false},
+ // Video Async Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", true},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", true},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", true},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", true},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", true},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", true}});
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void testDecoder() throws IOException {
+ File inputFile = new File(mInputFilePath + mInputFile);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+ if (trackCount <= 0) {
+ Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
+ return;
+ }
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+ if (mediaCodecs.size() <= 0) {
+ Log.e(TAG,
+ "No suitable codecs found for file: " + mInputFile
+ + " track : " + currentTrack + " mime: " + mime);
+ continue;
+ }
+ // Get samples from extractor
+ int sampleSize;
+ do {
+ sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo info = extractor.getBufferInfo();
+ ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+ dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+ bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+ inputBuffer.add(dataBuffer);
+ frameInfo.add(bufInfo);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = "
+ + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ } while (sampleSize > 0);
+ for (String codecName : mediaCodecs) {
+ FileOutputStream decodeOutputStream = null;
+ if (WRITE_OUTPUT) {
+ if (!Paths.get(mOutputFilePath).toFile().exists()) {
+ Files.createDirectories(Paths.get(mOutputFilePath));
+ }
+ File outFile = new File(mOutputFilePath + "decoder.out");
+ if (outFile.exists()) {
+ if (!outFile.delete()) {
+ Log.e(TAG, " Unable to delete existing file" + outFile.toString());
+ }
+ }
+ if (outFile.createNewFile()) {
+ decodeOutputStream = new FileOutputStream(outFile);
+ } else {
+ Log.e(TAG, "Unable to create file: " + outFile.toString());
+ }
+ }
+ Decoder decoder = new Decoder();
+ decoder.setupDecoder(decodeOutputStream);
+ int status =
+ decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
+ decoder.deInitCodec();
+ if (status == 0) {
+ decoder.dumpStatistics(
+ mInputFile + " " + codecName, extractor.getClipDuration());
+ Log.i(TAG,
+ "Decoding Successful for file: " + mInputFile
+ + " with codec: " + codecName);
+ } else {
+ Log.e(TAG,
+ "Decoder returned error " + status + " for file: " + mInputFile
+ + " with codec: " + codecName);
+ }
+ decoder.resetDecoder();
+ if (decodeOutputStream != null) {
+ decodeOutputStream.close();
+ }
+ }
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBuffer.clear();
+ frameInfo.clear();
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ } else {
+ Log.w(TAG,
+ "Warning: Test Skipped. Cannot find " + mInputFile + " in directory "
+ + mInputFilePath);
+ }
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
new file mode 100644
index 0000000..08035c9
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
@@ -0,0 +1,39 @@
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.os.Build;
+
+import java.util.ArrayList;
+
+public class CodecUtils {
+ private CodecUtils() {}
+
+ /**
+ * Queries the MediaCodecList and returns codec names of supported codecs.
+ *
+ * @param mimeType Mime type of input
+ * @param isEncoder Specifies encoder or decoder
+ * @return ArrayList of codec names
+ */
+ public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ ArrayList<String> supportedCodecs = new ArrayList<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (isEncoder != codecInfo.isEncoder()) {
+ continue;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) {
+ continue;
+ }
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mimeType)) {
+ supportedCodecs.add(codecInfo.getName());
+ }
+ }
+ }
+ return supportedCodecs;
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
new file mode 100644
index 0000000..2cd27c2
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2019 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 com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Decoder {
+ private static final String TAG = "Decoder";
+ private static final boolean DEBUG = false;
+ private static final int kQueueDequeueTimeoutUs = 1000;
+
+ private final Object mLock = new Object();
+ private MediaCodec mCodec;
+ private ArrayList<BufferInfo> mInputBufferInfo;
+ private Stats mStats;
+
+ private boolean mSawInputEOS;
+ private boolean mSawOutputEOS;
+ private boolean mSignalledError;
+
+ private int mNumOutputFrame;
+ private int mIndex;
+
+ private ArrayList<ByteBuffer> mInputBuffer;
+ private FileOutputStream mOutputStream;
+
+ public Decoder() { mStats = new Stats(); }
+
+ /**
+ * Setup of decoder
+ *
+ * @param outputStream Will dump the output in this stream if not null.
+ */
+ public void setupDecoder(FileOutputStream outputStream) {
+ mSignalledError = false;
+ mOutputStream = outputStream;
+ }
+
+ private MediaCodec createCodec(String codecName, MediaFormat format) throws IOException {
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ try {
+ MediaCodec codec;
+ if (codecName.isEmpty()) {
+ Log.i(TAG, "File mime type: " + mime);
+ if (mime != null) {
+ codec = MediaCodec.createDecoderByType(mime);
+ Log.i(TAG, "Decoder created for mime type " + mime);
+ return codec;
+ } else {
+ Log.e(TAG, "Mime type is null, please specify a mime type to create decoder");
+ return null;
+ }
+ } else {
+ codec = MediaCodec.createByCodecName(codecName);
+ Log.i(TAG, "Decoder created with codec name: " + codecName + " mime: " + mime);
+ return codec;
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Failed to create decoder for " + codecName + " mime:" + mime);
+ return null;
+ }
+ }
+
+ /**
+ * Decodes the given input buffer,
+ * provided valid list of buffer info and format are passed as inputs.
+ *
+ * @param inputBuffer Decode the provided list of ByteBuffers
+ * @param inputBufferInfo List of buffer info corresponding to provided input buffers
+ * @param asyncMode Will run on async implementation if true
+ * @param format For creating the decoder if codec name is empty and configuring it
+ * @param codecName Will create the decoder with codecName
+ * @return 0 if decode was successful , -1 for fail, -2 for decoder not created
+ * @throws IOException if the codec cannot be created.
+ */
+ public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
+ @NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
+ @NonNull MediaFormat format, String codecName) throws IOException {
+ mInputBuffer = new ArrayList<>(inputBuffer.size());
+ mInputBuffer.addAll(inputBuffer);
+ mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
+ mInputBufferInfo.addAll(inputBufferInfo);
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mNumOutputFrame = 0;
+ mIndex = 0;
+ long sTime = mStats.getCurTime();
+ mCodec = createCodec(codecName, format);
+ if (mCodec == null) {
+ return -2;
+ }
+ if (asyncMode) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(
+ @NonNull MediaCodec mediaCodec, int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mediaCodec);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onOutputFormatChanged(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+
+ @Override
+ public void onError(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+ mSignalledError = true;
+ Log.e(TAG, "Codec Error: " + e.toString());
+ e.printStackTrace();
+ synchronized (mLock) { mLock.notify(); }
+ }
+ });
+ }
+ int isEncoder = 0;
+ if (DEBUG) {
+ Log.d(TAG, "Media Format : " + format.toString());
+ }
+ mCodec.configure(format, null, null, isEncoder);
+ mCodec.start();
+ Log.i(TAG, "Codec started ");
+ long eTime = mStats.getCurTime();
+ mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+ mStats.setStartTime();
+ if (asyncMode) {
+ try {
+ synchronized (mLock) { mLock.wait(); }
+ if (mSignalledError) {
+ return -1;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+ if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueInputBuffer "
+ + " returned invalid index : " + inputBufferId);
+ return -1;
+ }
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mCodec);
+ }
+ /* Dequeue output data */
+ BufferInfo outputBufferInfo = new BufferInfo();
+ int outputBufferId =
+ mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+ if (outputBufferId < 0) {
+ if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat outFormat = mCodec.getOutputFormat();
+ Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ Log.i(TAG, "Ignoring deprecated flag: INFO_OUTPUT_BUFFERS_CHANGED");
+ } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueOutputBuffer"
+ + " returned invalid index " + outputBufferId);
+ return -1;
+ }
+ } else {
+ mStats.addOutputTime();
+ if (DEBUG) {
+ Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+ }
+ onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+ }
+ if (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ Log.i(TAG, "Saw output EOS");
+ }
+ }
+ }
+ mInputBuffer.clear();
+ mInputBufferInfo.clear();
+ return 0;
+ }
+
+ /**
+ * Stops the codec and releases codec resources.
+ */
+ public void deInitCodec() {
+ long sTime = mStats.getCurTime();
+ if (mCodec != null) {
+ mCodec.stop();
+ mCodec.release();
+ mCodec = null;
+ }
+ long eTime = mStats.getCurTime();
+ mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+ }
+
+ /**
+ * Prints out the statistics in the information log
+ *
+ * @param inputReference The operation being performed, in this case decode
+ * @param durationUs Duration of the clip in microseconds
+ */
+ public void dumpStatistics(String inputReference, long durationUs) {
+ String operation = "decode";
+ mStats.dumpStatistics(operation, inputReference, durationUs);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetDecoder() { mStats.reset(); }
+
+ private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
+ if ((inputBufferId >= 0) && !mSawInputEOS) {
+ ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
+ BufferInfo bufInfo = mInputBufferInfo.get(mIndex);
+ inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+ mIndex++;
+ if (bufInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ mSawInputEOS = true;
+ Log.i(TAG, "Saw input EOS");
+ }
+ mStats.addFrameSize(bufInfo.size);
+ mediaCodec.queueInputBuffer(inputBufferId, bufInfo.offset, bufInfo.size,
+ bufInfo.presentationTimeUs, bufInfo.flags);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Codec Input: "
+ + "flag = " + bufInfo.flags + " timestamp = "
+ + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ }
+ }
+
+ private void onOutputAvailable(
+ MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ return;
+ }
+ mNumOutputFrame++;
+ if (DEBUG) {
+ Log.d(TAG,
+ "In OutputBufferAvailable ,"
+ + " output frame number = " + mNumOutputFrame);
+ }
+ if (mOutputStream != null) {
+ try {
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ }
+ }
+ mediaCodec.releaseOutputBuffer(outputBufferId, false);
+ mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ }
+}
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 5dd83dd..d1354b3 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -96,3 +96,10 @@
```
adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.ExtractorTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
```
+
+## Decoder
+
+The test decodes input stream and benchmarks the decoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.DecoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 6cb42d6..242178f 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -72,24 +72,7 @@
vector<AMediaCodecBufferInfo> frameInfo;
AMediaCodecBufferInfo info;
uint32_t inputBufferOffset = 0;
- int32_t idx = 0;
- // Get CSD data
- while (1) {
- void *csdBuffer = extractor->getCSDSample(info, idx);
- if (!csdBuffer || !info.size) break;
-
- // copy the meta data and buffer to be passed to decoder
- if (inputBufferOffset + info.size > kMaxBufferSize) {
- cout << "[ WARN ] Test Skipped. Memory allocated not sufficient\n";
- free(inputBuffer);
- return;
- }
- memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
- frameInfo.push_back(info);
- inputBufferOffset += info.size;
- idx++;
- }
// Get frame data
while (1) {
status = extractor->getFrameSample(info);
@@ -135,6 +118,7 @@
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
INSTANTIATE_TEST_SUITE_P(
@@ -144,6 +128,7 @@
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
INSTANTIATE_TEST_SUITE_P(VideDecoderSyncTest, DecoderTest,
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index 574083d..9f42c64 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -72,24 +72,6 @@
vector<AMediaCodecBufferInfo> frameInfo;
AMediaCodecBufferInfo info;
uint32_t inputBufferOffset = 0;
- int32_t idx = 0;
-
- // Get CSD data
- while (1) {
- void *csdBuffer = extractor->getCSDSample(info, idx);
- if (!csdBuffer || !info.size) break;
-
- // copy the meta data and buffer to be passed to decoder
- if (inputBufferOffset + info.size > kMaxBufferSize) {
- cout << "[ WARN ] Test Skipped. Memory allocated not sufficient\n";
- free(inputBuffer);
- return;
- }
- memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
- frameInfo.push_back(info);
- inputBufferOffset += info.size;
- idx++;
- }
// Get frame data
while (1) {
@@ -189,6 +171,7 @@
::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", false),
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
INSTANTIATE_TEST_SUITE_P(
@@ -196,6 +179,7 @@
::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", true),
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
INSTANTIATE_TEST_SUITE_P(VideEncoderSyncTest, EncoderTest,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 72221a8..3223530 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1093,8 +1093,9 @@
}
audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+ .channel_mask = config->channel_mask,
.format = config->format,
- .channel_mask = config->channel_mask };
+ };
*portId = PolicyAudioPort::getNextUniqueId();
sp<TrackClientDescriptor> clientDesc =
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 7dfc205..2319838 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -422,12 +422,18 @@
// AND is on TOP
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR the client source is virtual (remote submix, call audio TX or RX...)
+// OR the client source is HOTWORD
+// AND is on TOP
+// OR all active clients are using HOTWORD source
+// AND no call is active
+// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// OR Any client
// AND The assistant is not on TOP
// AND is on TOP or latest started
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+
sp<AudioRecordClient> topActive;
sp<AudioRecordClient> latestActive;
sp<AudioRecordClient> latestSensitiveActive;
@@ -442,6 +448,7 @@
bool rttCallActive =
(mPhoneState == AUDIO_MODE_IN_CALL || mPhoneState == AUDIO_MODE_IN_COMMUNICATION)
&& mUidPolicy->isRttEnabled();
+ bool onlyHotwordActive = true;
// if Sensor Privacy is enabled then all recordings should be silenced.
if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -473,12 +480,11 @@
isAssistantOnTop = true;
}
}
- // Assistant capturing for HOTWORD or Accessibility services not considered
+ // Client capturing for HOTWORD or Accessibility services not considered
// for latest active to avoid masking regular clients started before
if (current->startTimeNs > latestStartNs
- && !((current->attributes.source == AUDIO_SOURCE_HOTWORD
- || isA11yOnTop || rttCallActive)
- && isAssistant)
+ && !(current->attributes.source == AUDIO_SOURCE_HOTWORD
+ || ((isA11yOnTop || rttCallActive) && isAssistant))
&& !isAccessibility) {
latestActive = current;
latestStartNs = current->startTimeNs;
@@ -490,6 +496,9 @@
}
isSensitiveActive = true;
}
+ if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
+ onlyHotwordActive = false;
+ }
}
// if no active client with UI on Top, consider latest active as top
@@ -556,6 +565,14 @@
allowCapture = true;
}
}
+ } else if (source == AUDIO_SOURCE_HOTWORD) {
+ // For HOTWORD source allow capture when not on TOP if:
+ // All active clients are using HOTWORD source
+ // AND no call is active
+ // OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ if (onlyHotwordActive && !(isInCall && !current->canCaptureOutput)) {
+ allowCapture = true;
+ }
}
setAppState_l(current->portId,
allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 42afc6b..f0cb9c1 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -567,7 +567,7 @@
mapping.versionCode = versionCode;
mapping.expiration = now + PKG_EXPIRATION_NS;
ALOGV("%s: adding uid %d pkg '%s' expiration: %lld",
- __func__, uid, pkg.c_str(), (long long)mapping.expiration);
+ __func__, uid, mapping.pkg.c_str(), (long long)mapping.expiration);
mPkgMappings[uid] = mapping;
}