Merge "aaudio: clear data buffer before use" into sc-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index dc22628..a86d2b9 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -84,6 +84,7 @@
name: "com.android.media",
manifest: "manifest.json",
defaults: ["com.android.media-defaults"],
+ prebuilts: ["current_sdkinfo"],
}
linker_config {
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index c77aeeb..946ec17 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -2323,4 +2323,28 @@
return unexpected(BAD_VALUE);
}
+ConversionResult<TrackSecondaryOutputInfoPair>
+aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair(
+ const media::TrackSecondaryOutputInfo& aidl) {
+ TrackSecondaryOutputInfoPair trackSecondaryOutputInfoPair;
+ trackSecondaryOutputInfoPair.first =
+ VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.portId));
+ trackSecondaryOutputInfoPair.second =
+ VALUE_OR_RETURN(convertContainer<std::vector<audio_port_handle_t>>(
+ aidl.secondaryOutputIds, aidl2legacy_int32_t_audio_io_handle_t));
+ return trackSecondaryOutputInfoPair;
+}
+
+ConversionResult<media::TrackSecondaryOutputInfo>
+legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo(
+ const TrackSecondaryOutputInfoPair& legacy) {
+ media::TrackSecondaryOutputInfo trackSecondaryOutputInfo;
+ trackSecondaryOutputInfo.portId =
+ VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy.first));
+ trackSecondaryOutputInfo.secondaryOutputIds =
+ VALUE_OR_RETURN(convertContainer<std::vector<int32_t>>(
+ legacy.second, legacy2aidl_audio_io_handle_t_int32_t));
+ return trackSecondaryOutputInfo;
+}
+
} // namespace android
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 19d68a0..43f9660 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -351,6 +351,7 @@
"aidl/android/media/AudioVibratorInfo.aidl",
"aidl/android/media/EffectDescriptor.aidl",
"aidl/android/media/ExtraAudioDescriptor.aidl",
+ "aidl/android/media/TrackSecondaryOutputInfo.aidl",
],
imports: [
"audio_common-aidl",
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 389b73f..0564cdf 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -743,6 +743,16 @@
return statusTFromBinderStatus(mDelegate->setVibratorInfos(vibratorInfos));
}
+status_t AudioFlingerClientAdapter::updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs) {
+ std::vector<media::TrackSecondaryOutputInfo> trackSecondaryOutputInfos =
+ VALUE_OR_RETURN_STATUS(
+ convertContainer<std::vector<media::TrackSecondaryOutputInfo>>(
+ trackSecondaryOutputs,
+ legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo));
+ return statusTFromBinderStatus(mDelegate->updateSecondaryOutputs(trackSecondaryOutputInfos));
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// AudioFlingerServerAdapter
@@ -1199,4 +1209,13 @@
return Status::fromStatusT(mDelegate->setVibratorInfos(vibratorInfos));
}
+Status AudioFlingerServerAdapter::updateSecondaryOutputs(
+ const std::vector<media::TrackSecondaryOutputInfo>& trackSecondaryOutputInfos) {
+ TrackSecondaryOutputsMap trackSecondaryOutputs =
+ VALUE_OR_RETURN_BINDER(convertContainer<TrackSecondaryOutputsMap>(
+ trackSecondaryOutputInfos,
+ aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair));
+ return Status::fromStatusT(mDelegate->updateSecondaryOutputs(trackSecondaryOutputs));
+}
+
} // namespace android
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index abbced5..d2cae6d 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -40,6 +40,7 @@
import android.media.IAudioTrack;
import android.media.MicrophoneInfoData;
import android.media.RenderPosition;
+import android.media.TrackSecondaryOutputInfo;
import android.media.audio.common.AudioFormat;
/**
@@ -207,4 +208,9 @@
// Set vibrators' information.
// The value will be used to initialize HapticGenerator.
void setVibratorInfos(in AudioVibratorInfo[] vibratorInfos);
+
+ // Update secondary outputs.
+ // This usually happens when there is a dynamic policy registered.
+ void updateSecondaryOutputs(
+ in TrackSecondaryOutputInfo[] trackSecondaryOutputInfos);
}
diff --git a/media/libaudioclient/aidl/android/media/TrackSecondaryOutputInfo.aidl b/media/libaudioclient/aidl/android/media/TrackSecondaryOutputInfo.aidl
new file mode 100644
index 0000000..113328e
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/TrackSecondaryOutputInfo.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 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;
+
+/**
+ * This is a class that contains port handle for a track and handles for all secondary
+ * outputs of the track.
+ * @hide
+ */
+parcelable TrackSecondaryOutputInfo {
+ int portId; // audio_port_handle_t
+ int[] secondaryOutputIds; // audio_io_handle_t[]
+}
\ No newline at end of file
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index 1dd9d60..4ec69c7 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -50,6 +50,7 @@
#include <android/media/AudioUniqueIdUse.h>
#include <android/media/EffectDescriptor.h>
#include <android/media/ExtraAudioDescriptor.h>
+#include <android/media/TrackSecondaryOutputInfo.h>
#include <android/media/SharedFileRegion.h>
#include <binder/IMemory.h>
@@ -407,6 +408,13 @@
legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(
const audio_encapsulation_type_t & legacy);
+using TrackSecondaryOutputInfoPair = std::pair<audio_port_handle_t, std::vector<audio_io_handle_t>>;
+ConversionResult<TrackSecondaryOutputInfoPair>
+aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair(
+ const media::TrackSecondaryOutputInfo& aidl);
+ConversionResult<media::TrackSecondaryOutputInfo>
+legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo(
+ const TrackSecondaryOutputInfoPair& legacy);
} // namespace android
diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h
index 8e446ea..5dfe5fc 100644
--- a/media/libaudioclient/include/media/AudioCommonTypes.h
+++ b/media/libaudioclient/include/media/AudioCommonTypes.h
@@ -29,6 +29,8 @@
using AttributesVector = std::vector<audio_attributes_t>;
using StreamTypeVector = std::vector<audio_stream_type_t>;
+using TrackSecondaryOutputsMap = std::map<audio_port_handle_t, std::vector<audio_io_handle_t>>;
+
constexpr bool operator==(const audio_attributes_t &lhs, const audio_attributes_t &rhs)
{
return lhs.usage == rhs.usage && lhs.content_type == rhs.content_type &&
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 3a04569..3a4868e 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -26,12 +26,14 @@
#include <binder/IInterface.h>
#include <media/AidlConversion.h>
#include <media/AudioClient.h>
+#include <media/AudioCommonTypes.h>
#include <media/DeviceDescriptorBase.h>
#include <system/audio.h>
#include <system/audio_effect.h>
#include <system/audio_policy.h>
#include <utils/String8.h>
#include <media/MicrophoneInfo.h>
+#include <map>
#include <string>
#include <vector>
@@ -55,6 +57,7 @@
#include "android/media/OpenInputResponse.h"
#include "android/media/OpenOutputRequest.h"
#include "android/media/OpenOutputResponse.h"
+#include "android/media/TrackSecondaryOutputInfo.h"
namespace android {
@@ -338,6 +341,9 @@
// The values will be used to initialize HapticGenerator.
virtual status_t setVibratorInfos(
const std::vector<media::AudioVibratorInfo>& vibratorInfos) = 0;
+
+ virtual status_t updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs) = 0;
};
/**
@@ -430,6 +436,8 @@
status_t getMicrophones(std::vector<media::MicrophoneInfo>* microphones) override;
status_t setAudioHalPids(const std::vector<pid_t>& pids) override;
status_t setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos) override;
+ status_t updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
private:
const sp<media::IAudioFlingerService> mDelegate;
@@ -513,6 +521,7 @@
SET_EFFECT_SUSPENDED = media::BnAudioFlingerService::TRANSACTION_setEffectSuspended,
SET_AUDIO_HAL_PIDS = media::BnAudioFlingerService::TRANSACTION_setAudioHalPids,
SET_VIBRATOR_INFOS = media::BnAudioFlingerService::TRANSACTION_setVibratorInfos,
+ UPDATE_SECONDARY_OUTPUTS = media::BnAudioFlingerService::TRANSACTION_updateSecondaryOutputs,
};
/**
@@ -619,6 +628,8 @@
Status getMicrophones(std::vector<media::MicrophoneInfoData>* _aidl_return) override;
Status setAudioHalPids(const std::vector<int32_t>& pids) override;
Status setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos) override;
+ Status updateSecondaryOutputs(
+ const std::vector<media::TrackSecondaryOutputInfo>& trackSecondaryOutputInfos) override;
private:
const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index e96c041..b26d028 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -18,11 +18,11 @@
],
}
-cc_library_shared {
+cc_library {
name: "libdownmix",
-
+ host_supported: true,
vendor: true,
- srcs: ["EffectDownmix.c"],
+ srcs: ["EffectDownmix.cpp"],
shared_libs: [
"libaudioutils",
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.cpp
similarity index 77%
rename from media/libeffects/downmix/EffectDownmix.c
rename to media/libeffects/downmix/EffectDownmix.cpp
index 5ca5525..f500bc3 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.cpp
@@ -16,32 +16,72 @@
#define LOG_TAG "EffectDownmix"
//#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-
#include <log/log.h>
#include "EffectDownmix.h"
+#include <math.h>
// Do not submit with DOWNMIX_TEST_CHANNEL_INDEX defined, strictly for testing
//#define DOWNMIX_TEST_CHANNEL_INDEX 0
// Do not submit with DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER defined, strictly for testing
//#define DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER 0
-#define MINUS_3_DB_IN_FLOAT 0.70710678f // -3dB = 0.70710678f
-const audio_format_t gTargetFormat = AUDIO_FORMAT_PCM_FLOAT;
+#define MINUS_3_DB_IN_FLOAT M_SQRT1_2 // -3dB = 0.70710678
-// subset of possible audio_channel_mask_t values, and AUDIO_CHANNEL_OUT_* renamed to CHANNEL_MASK_*
typedef enum {
- CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD_BACK,
- CHANNEL_MASK_QUAD_SIDE = AUDIO_CHANNEL_OUT_QUAD_SIDE,
- CHANNEL_MASK_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1_BACK,
- CHANNEL_MASK_5POINT1_SIDE = AUDIO_CHANNEL_OUT_5POINT1_SIDE,
- CHANNEL_MASK_7POINT1 = AUDIO_CHANNEL_OUT_7POINT1,
-} downmix_input_channel_mask_t;
+ DOWNMIX_STATE_UNINITIALIZED,
+ DOWNMIX_STATE_INITIALIZED,
+ DOWNMIX_STATE_ACTIVE,
+} downmix_state_t;
+
+/* parameters for each downmixer */
+typedef struct {
+ downmix_state_t state;
+ downmix_type_t type;
+ bool apply_volume_correction;
+ uint8_t input_channel_count;
+} downmix_object_t;
+
+typedef struct downmix_module_s {
+ const struct effect_interface_s *itfe;
+ effect_config_t config;
+ downmix_object_t context;
+} downmix_module_t;
+
+
+// Audio Effect API
+static int32_t DownmixLib_Create(const effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_handle_t *pHandle);
+static int32_t DownmixLib_Release(effect_handle_t handle);
+static int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid,
+ effect_descriptor_t *pDescriptor);
+static int32_t Downmix_Process(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer);
+static int32_t Downmix_Command(effect_handle_t self,
+ uint32_t cmdCode,
+ uint32_t cmdSize,
+ void *pCmdData,
+ uint32_t *replySize,
+ void *pReplyData);
+static int32_t Downmix_GetDescriptor(effect_handle_t self,
+ effect_descriptor_t *pDescriptor);
+
+// Internal methods
+static int Downmix_Init(downmix_module_t *pDwmModule);
+static int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init);
+static int Downmix_Reset(downmix_object_t *pDownmixer, bool init);
+static int Downmix_setParameter(
+ downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue);
+static int Downmix_getParameter(
+ downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue);
+static void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate);
+static void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate);
+static void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate);
+static bool Downmix_foldGeneric(
+ uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate);
// effect_handle_t interface implementation for downmix effect
const struct effect_interface_s gDownmixInterface = {
@@ -63,7 +103,6 @@
.get_descriptor = DownmixLib_GetDescriptor,
};
-
// AOSP insert downmix UUID: 93f04452-e4fe-41cc-91f9-e475b6d1d69f
static const effect_descriptor_t gDownmixDescriptor = {
EFFECT_UIID_DOWNMIX__, //type
@@ -84,16 +123,8 @@
// number of effects in this library
const int kNbEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
-static LVM_FLOAT clamp_float(LVM_FLOAT a) {
- if (a > 1.0f) {
- return 1.0f;
- }
- else if (a < -1.0f) {
- return -1.0f;
- }
- else {
- return a;
- }
+static inline float clamp_float(float value) {
+ return fmin(fmax(value, -1.f), 1.f);
}
/*----------------------------------------------------------------------------
@@ -103,7 +134,7 @@
// strictly for testing, logs the indices of the channels for a given mask,
// uses the same code as Downmix_foldGeneric()
void Downmix_testIndexComputation(uint32_t mask) {
- ALOGI("Testing index computation for 0x%" PRIx32 ":", mask);
+ ALOGI("Testing index computation for %#x:", mask);
// check against unsupported channels
if (mask & kUnsupported) {
ALOGE("Unsupported channels (top or front left/right of center)");
@@ -162,29 +193,10 @@
return false;
}
// check against unsupported channels
- if (mask & kUnsupported) {
- ALOGE("Unsupported channels (top or front left/right of center)");
+ if (mask & ~AUDIO_CHANNEL_OUT_22POINT2) {
+ ALOGE("Unsupported channels in %u", mask & ~AUDIO_CHANNEL_OUT_22POINT2);
return false;
}
- // verify has FL/FR
- if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) {
- ALOGE("Front channels must be present");
- return false;
- }
- // verify uses SIDE as a pair (ok if not using SIDE at all)
- if ((mask & kSides) != 0) {
- if ((mask & kSides) != kSides) {
- ALOGE("Side channels must be used as a pair");
- return false;
- }
- }
- // verify uses BACK as a pair (ok if not using BACK at all)
- if ((mask & kBacks) != 0) {
- if ((mask & kBacks) != kBacks) {
- ALOGE("Back channels must be used as a pair");
- return false;
- }
- }
return true;
}
@@ -194,9 +206,9 @@
/*--- Effect Library Interface Implementation ---*/
-int32_t DownmixLib_Create(const effect_uuid_t *uuid,
- int32_t sessionId __unused,
- int32_t ioId __unused,
+static int32_t DownmixLib_Create(const effect_uuid_t *uuid,
+ int32_t /* sessionId */,
+ int32_t /* ioId */,
effect_handle_t *pHandle) {
int ret;
int i;
@@ -210,9 +222,9 @@
ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should work:");
Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_CENTER);
- Downmix_testIndexComputation(CHANNEL_MASK_QUAD_SIDE | CHANNEL_MASK_QUAD_BACK);
- Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_SIDE | AUDIO_CHANNEL_OUT_BACK_CENTER);
- Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_BACK | AUDIO_CHANNEL_OUT_BACK_CENTER);
+ Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_QUAD_SIDE | AUDIO_CHANNEL_OUT_QUAD_BACK);
+ Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_5POINT1_SIDE | AUDIO_CHANNEL_OUT_BACK_CENTER);
+ Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_5POINT1_BACK | AUDIO_CHANNEL_OUT_BACK_CENTER);
// shouldn't work (will log an error, won't display channel indices)
ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should NOT work:");
Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
@@ -240,7 +252,7 @@
return -ENOENT;
}
- module = malloc(sizeof(downmix_module_t));
+ module = new downmix_module_t{};
module->itfe = &gDownmixInterface;
@@ -260,8 +272,7 @@
return 0;
}
-
-int32_t DownmixLib_Release(effect_handle_t handle) {
+static int32_t DownmixLib_Release(effect_handle_t handle) {
downmix_module_t *pDwmModule = (downmix_module_t *)handle;
ALOGV("DownmixLib_Release() %p", handle);
@@ -271,12 +282,12 @@
pDwmModule->context.state = DOWNMIX_STATE_UNINITIALIZED;
- free(pDwmModule);
+ delete pDwmModule;
return 0;
}
-
-int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) {
+static int32_t DownmixLib_GetDescriptor(
+ const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) {
ALOGV("DownmixLib_GetDescriptor()");
int i;
@@ -289,7 +300,7 @@
ALOGV("DownmixLib_GetDescriptor() i=%d", i);
if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t));
- ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %" PRIx32,
+ ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %#x",
i, gDescriptors[i]->uuid.timeLow);
return 0;
}
@@ -300,11 +311,11 @@
/*--- Effect Control Interface Implementation ---*/
-static int Downmix_Process(effect_handle_t self,
+static int32_t Downmix_Process(effect_handle_t self,
audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
downmix_object_t *pDownmixer;
- LVM_FLOAT *pSrc, *pDst;
+ float *pSrc, *pDst;
downmix_module_t *pDwmModule = (downmix_module_t *)self;
if (pDwmModule == NULL) {
@@ -327,8 +338,8 @@
return -ENODATA;
}
- pSrc = (LVM_FLOAT *) inBuffer->s16;
- pDst = (LVM_FLOAT *) outBuffer->s16;
+ pSrc = inBuffer->f32;
+ pDst = outBuffer->f32;
size_t numFrames = outBuffer->frameCount;
const bool accumulate =
@@ -362,29 +373,29 @@
// bypass the optimized downmix routines for the common formats
if (!Downmix_foldGeneric(
downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
- ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
+ ALOGE("Multichannel configuration %#x is not supported",
downmixInputChannelMask);
return -EINVAL;
}
break;
#endif
// optimize for the common formats
- switch((downmix_input_channel_mask_t)downmixInputChannelMask) {
- case CHANNEL_MASK_QUAD_BACK:
- case CHANNEL_MASK_QUAD_SIDE:
+ switch (downmixInputChannelMask) {
+ case AUDIO_CHANNEL_OUT_QUAD_BACK:
+ case AUDIO_CHANNEL_OUT_QUAD_SIDE:
Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate);
break;
- case CHANNEL_MASK_5POINT1_BACK:
- case CHANNEL_MASK_5POINT1_SIDE:
+ case AUDIO_CHANNEL_OUT_5POINT1_BACK:
+ case AUDIO_CHANNEL_OUT_5POINT1_SIDE:
Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate);
break;
- case CHANNEL_MASK_7POINT1:
+ case AUDIO_CHANNEL_OUT_7POINT1:
Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate);
break;
default:
if (!Downmix_foldGeneric(
downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
- ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported",
+ ALOGE("Multichannel configuration %#x is not supported",
downmixInputChannelMask);
return -EINVAL;
}
@@ -399,7 +410,7 @@
return 0;
}
-static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
+static int32_t Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
void *pCmdData, uint32_t *replySize, void *pReplyData) {
downmix_module_t *pDwmModule = (downmix_module_t *) self;
@@ -411,7 +422,7 @@
pDownmixer = (downmix_object_t*) &pDwmModule->context;
- ALOGV("Downmix_Command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize);
+ ALOGV("Downmix_Command command %u cmdSize %u", cmdCode, cmdSize);
switch (cmdCode) {
case EFFECT_CMD_INIT:
@@ -434,8 +445,8 @@
Downmix_Reset(pDownmixer, false);
break;
- case EFFECT_CMD_GET_PARAM:
- ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %" PRIu32 ", pReplyData: %p",
+ case EFFECT_CMD_GET_PARAM: {
+ ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %u, pReplyData: %p",
pCmdData, *replySize, pReplyData);
if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
pReplyData == NULL || replySize == NULL ||
@@ -444,15 +455,15 @@
}
effect_param_t *rep = (effect_param_t *) pReplyData;
memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t));
- ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %" PRId32 ", replySize %" PRIu32,
+ ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %d, replySize %u",
*(int32_t *)rep->data, rep->vsize);
rep->status = Downmix_getParameter(pDownmixer, *(int32_t *)rep->data, &rep->vsize,
rep->data + sizeof(int32_t));
*replySize = sizeof(effect_param_t) + sizeof(int32_t) + rep->vsize;
break;
-
- case EFFECT_CMD_SET_PARAM:
- ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %" PRIu32
+ }
+ case EFFECT_CMD_SET_PARAM: {
+ ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %u"
", pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
|| pReplyData == NULL || replySize == NULL || *replySize != (int)sizeof(int32_t)) {
@@ -466,6 +477,7 @@
*(int *)pReplyData = Downmix_setParameter(pDownmixer, *(int32_t *)cmd->data,
cmd->vsize, cmd->data + sizeof(int32_t));
break;
+ }
case EFFECT_CMD_SET_PARAM_DEFERRED:
//FIXME implement
@@ -506,7 +518,7 @@
return -EINVAL;
}
// FIXME change type if playing on headset vs speaker
- ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: 0x%08" PRIx32, *(uint32_t *)pCmdData);
+ ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: %#x", *(uint32_t *)pCmdData);
break;
case EFFECT_CMD_SET_VOLUME: {
@@ -526,7 +538,7 @@
if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
return -EINVAL;
}
- ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %" PRIu32, *(uint32_t *)pCmdData);
+ ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %u", *(uint32_t *)pCmdData);
break;
case EFFECT_CMD_SET_CONFIG_REVERSE:
@@ -535,15 +547,14 @@
break;
default:
- ALOGW("Downmix_Command invalid command %" PRIu32, cmdCode);
+ ALOGW("Downmix_Command invalid command %u", cmdCode);
return -EINVAL;
}
return 0;
}
-
-int Downmix_GetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor)
+static int32_t Downmix_GetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor)
{
downmix_module_t *pDwnmxModule = (downmix_module_t *) self;
@@ -591,7 +602,7 @@
*----------------------------------------------------------------------------
*/
-int Downmix_Init(downmix_module_t *pDwmModule) {
+static int Downmix_Init(downmix_module_t *pDwmModule) {
ALOGV("Downmix_Init module %p", pDwmModule);
int ret = 0;
@@ -599,7 +610,7 @@
memset(&pDwmModule->context, 0, sizeof(downmix_object_t));
pDwmModule->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
- pDwmModule->config.inputCfg.format = gTargetFormat;
+ pDwmModule->config.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
pDwmModule->config.inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
pDwmModule->config.inputCfg.bufferProvider.getBuffer = NULL;
pDwmModule->config.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -611,7 +622,7 @@
// set a default value for the access mode, but should be overwritten by caller
pDwmModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
- pDwmModule->config.outputCfg.format = gTargetFormat;
+ pDwmModule->config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
pDwmModule->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
pDwmModule->config.outputCfg.bufferProvider.getBuffer = NULL;
pDwmModule->config.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -651,15 +662,15 @@
*----------------------------------------------------------------------------
*/
-int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init) {
+static int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init) {
downmix_object_t *pDownmixer = &pDwmModule->context;
// Check configuration compatibility with build options, and effect capabilities
if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate
- || pConfig->outputCfg.channels != DOWNMIX_OUTPUT_CHANNELS
- || pConfig->inputCfg.format != gTargetFormat
- || pConfig->outputCfg.format != gTargetFormat) {
+ || pConfig->outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
+ || pConfig->inputCfg.format != AUDIO_FORMAT_PCM_FLOAT
+ || pConfig->outputCfg.format != AUDIO_FORMAT_PCM_FLOAT) {
ALOGE("Downmix_Configure error: invalid config");
return -EINVAL;
}
@@ -709,7 +720,7 @@
*----------------------------------------------------------------------------
*/
-int Downmix_Reset(downmix_object_t *pDownmixer __unused, bool init __unused) {
+static int Downmix_Reset(downmix_object_t* /* pDownmixer */, bool /* init */) {
// nothing to do here
return 0;
}
@@ -736,31 +747,32 @@
*
*----------------------------------------------------------------------------
*/
-int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) {
+static int Downmix_setParameter(
+ downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) {
int16_t value16;
- ALOGV("Downmix_setParameter, context %p, param %" PRId32 ", value16 %" PRId16 ", value32 %" PRId32,
+ ALOGV("Downmix_setParameter, context %p, param %d, value16 %d, value32 %d",
pDownmixer, param, *(int16_t *)pValue, *(int32_t *)pValue);
switch (param) {
case DOWNMIX_PARAM_TYPE:
if (size != sizeof(downmix_type_t)) {
- ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %" PRIu32 ", should be %zu",
+ ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %u, should be %zu",
size, sizeof(downmix_type_t));
return -EINVAL;
}
value16 = *(int16_t *)pValue;
- ALOGV("set DOWNMIX_PARAM_TYPE, type %" PRId16, value16);
+ ALOGV("set DOWNMIX_PARAM_TYPE, type %d", value16);
if (!((value16 > DOWNMIX_TYPE_INVALID) && (value16 <= DOWNMIX_TYPE_LAST))) {
- ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %" PRId16, value16);
+ ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %d", value16);
return -EINVAL;
} else {
pDownmixer->type = (downmix_type_t) value16;
break;
default:
- ALOGE("Downmix_setParameter unknown parameter %" PRId32, param);
+ ALOGE("Downmix_setParameter unknown parameter %d", param);
return -EINVAL;
}
}
@@ -792,24 +804,25 @@
*
*----------------------------------------------------------------------------
*/
-int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue) {
+static int Downmix_getParameter(
+ downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue) {
int16_t *pValue16;
switch (param) {
case DOWNMIX_PARAM_TYPE:
if (*pSize < sizeof(int16_t)) {
- ALOGE("Downmix_getParameter invalid parameter size %" PRIu32 " for DOWNMIX_PARAM_TYPE", *pSize);
+ ALOGE("Downmix_getParameter invalid parameter size %u for DOWNMIX_PARAM_TYPE", *pSize);
return -EINVAL;
}
pValue16 = (int16_t *)pValue;
*pValue16 = (int16_t) pDownmixer->type;
*pSize = sizeof(int16_t);
- ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %" PRId16, *pValue16);
+ ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %d", *pValue16);
break;
default:
- ALOGE("Downmix_getParameter unknown parameter %" PRId16, param);
+ ALOGE("Downmix_getParameter unknown parameter %d", param);
return -EINVAL;
}
@@ -834,7 +847,7 @@
*
*----------------------------------------------------------------------------
*/
-void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
// sample at index 0 is FL
// sample at index 1 is FR
// sample at index 2 is RL
@@ -879,8 +892,8 @@
*
*----------------------------------------------------------------------------
*/
-void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
- LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
+void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
+ float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
// sample at index 0 is FL
// sample at index 1 is FR
// sample at index 2 is FC
@@ -941,8 +954,8 @@
*
*----------------------------------------------------------------------------
*/
-void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
- LVM_FLOAT lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
+void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
+ float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
// sample at index 0 is FL
// sample at index 1 is FR
// sample at index 2 is FC
@@ -992,13 +1005,7 @@
* Downmix_foldGeneric()
*----------------------------------------------------------------------------
* Purpose:
- * downmix to stereo a multichannel signal whose format is:
- * - has FL/FR
- * - if using AUDIO_CHANNEL_OUT_SIDE*, it contains both left and right
- * - if using AUDIO_CHANNEL_OUT_BACK*, it contains both left and right
- * - doesn't use any of the AUDIO_CHANNEL_OUT_TOP* channels
- * - doesn't use any of the AUDIO_CHANNEL_OUT_FRONT_*_OF_CENTER channels
- * Only handles channel masks not enumerated in downmix_input_channel_mask_t
+ * downmix to stereo a multichannel signal of arbitrary channel position mask.
*
* Inputs:
* mask the channel mask of pSrc
@@ -1015,93 +1022,106 @@
*----------------------------------------------------------------------------
*/
bool Downmix_foldGeneric(
- uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate) {
+ uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate) {
if (!Downmix_validChannelMask(mask)) {
return false;
}
-
- const bool hasSides = (mask & kSides) != 0;
- const bool hasBacks = (mask & kBacks) != 0;
-
const int numChan = audio_channel_count_from_out_mask(mask);
- const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
- const bool hasLFE =
- ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
- const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
- // compute at what index each channel is: samples will be in the following order:
- // FL FR FC LFE BL BR BC SL SR
- // when a channel is not present, its index is set to the same as the index of the preceding
- // channel
- const int indexFC = hasFC ? 2 : 1; // front center
- const int indexLFE = hasLFE ? indexFC + 1 : indexFC; // low frequency
- const int indexBL = hasBacks ? indexLFE + 1 : indexLFE; // back left
- const int indexBR = hasBacks ? indexBL + 1 : indexBL; // back right
- const int indexBC = hasBC ? indexBR + 1 : indexBR; // back center
- const int indexSL = hasSides ? indexBC + 1 : indexBC; // side left
- const int indexSR = hasSides ? indexSL + 1 : indexSL; // side right
- LVM_FLOAT lt, rt, centersLfeContrib;
- // code is mostly duplicated between the two values of accumulate to avoid repeating the test
- // for every sample
- if (accumulate) {
- while (numFrames) {
- // compute contribution of FC, BC and LFE
- centersLfeContrib = 0;
- if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
- if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
- if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
- centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
- // always has FL/FR
- lt = pSrc[0];
- rt = pSrc[1];
- // mix in sides and backs
- if (hasSides) {
- lt += pSrc[indexSL];
- rt += pSrc[indexSR];
- }
- if (hasBacks) {
- lt += pSrc[indexBL];
- rt += pSrc[indexBR];
- }
- lt += centersLfeContrib;
- rt += centersLfeContrib;
- // accumulate in destination
- pDst[0] = clamp_float(pDst[0] + (lt / 2.0f));
- pDst[1] = clamp_float(pDst[1] + (rt / 2.0f));
- pSrc += numChan;
- pDst += 2;
- numFrames--;
+ // compute at what index each channel is: samples will be in the following order:
+ // FL FR FC LFE BL BR BC SL SR
+ //
+ // (transfer matrix)
+ // FL FR FC LFE BL BR BC SL SR
+ // 0.5 0.353 0.353 0.5 0.353 0.5
+ // 0.5 0.353 0.353 0.5 0.353 0.5
+
+ // derive the indices for the transfer matrix columns that have non-zero values.
+ int indexFL = -1;
+ int indexFR = -1;
+ int indexFC = -1;
+ int indexLFE = -1;
+ int indexBL = -1;
+ int indexBR = -1;
+ int indexBC = -1;
+ int indexSL = -1;
+ int indexSR = -1;
+ int index = 0;
+ for (unsigned tmp = mask;
+ (tmp & (AUDIO_CHANNEL_OUT_7POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER)) != 0;
+ ++index) {
+ const unsigned lowestBit = tmp & -(signed)tmp;
+ switch (lowestBit) {
+ case AUDIO_CHANNEL_OUT_FRONT_LEFT:
+ indexFL = index;
+ break;
+ case AUDIO_CHANNEL_OUT_FRONT_RIGHT:
+ indexFR = index;
+ break;
+ case AUDIO_CHANNEL_OUT_FRONT_CENTER:
+ indexFC = index;
+ break;
+ case AUDIO_CHANNEL_OUT_LOW_FREQUENCY:
+ indexLFE = index;
+ break;
+ case AUDIO_CHANNEL_OUT_BACK_LEFT:
+ indexBL = index;
+ break;
+ case AUDIO_CHANNEL_OUT_BACK_RIGHT:
+ indexBR = index;
+ break;
+ case AUDIO_CHANNEL_OUT_BACK_CENTER:
+ indexBC = index;
+ break;
+ case AUDIO_CHANNEL_OUT_SIDE_LEFT:
+ indexSL = index;
+ break;
+ case AUDIO_CHANNEL_OUT_SIDE_RIGHT:
+ indexSR = index;
+ break;
}
- } else {
- while (numFrames) {
- // compute contribution of FC, BC and LFE
- centersLfeContrib = 0;
- if (hasFC) { centersLfeContrib += pSrc[indexFC]; }
- if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
- if (hasBC) { centersLfeContrib += pSrc[indexBC]; }
- centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
- // always has FL/FR
- lt = pSrc[0];
- rt = pSrc[1];
- // mix in sides and backs
- if (hasSides) {
- lt += pSrc[indexSL];
- rt += pSrc[indexSR];
- }
- if (hasBacks) {
- lt += pSrc[indexBL];
- rt += pSrc[indexBR];
- }
- lt += centersLfeContrib;
- rt += centersLfeContrib;
- // store in destination
- pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above
- pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above
- pSrc += numChan;
- pDst += 2;
- numFrames--;
+ tmp ^= lowestBit;
+ }
+
+ // With good branch prediction, this should run reasonably fast.
+ // Also consider using a transfer matrix form.
+ while (numFrames) {
+ // compute contribution of FC, BC and LFE
+ float centersLfeContrib = 0;
+ if (indexFC >= 0) centersLfeContrib = pSrc[indexFC];
+ if (indexLFE >= 0) centersLfeContrib += pSrc[indexLFE];
+ if (indexBC >= 0) centersLfeContrib += pSrc[indexBC];
+ centersLfeContrib *= MINUS_3_DB_IN_FLOAT;
+
+ float ch[2];
+ ch[0] = centersLfeContrib;
+ ch[1] = centersLfeContrib;
+
+ // mix in left / right channels
+ if (indexFL >= 0) ch[0] += pSrc[indexFL];
+ if (indexFR >= 0) ch[1] += pSrc[indexFR];
+
+ if (indexSL >= 0) ch[0] += pSrc[indexSL];
+ if (indexSR >= 0) ch[1] += pSrc[indexSR]; // note pair checks enforce this if indexSL != 0
+
+ if (indexBL >= 0) ch[0] += pSrc[indexBL];
+ if (indexBR >= 0) ch[1] += pSrc[indexBR]; // note pair checks enforce this if indexBL != 0
+
+ // scale to prevent overflow.
+ ch[0] *= 0.5f;
+ ch[1] *= 0.5f;
+
+ if (accumulate) {
+ ch[0] += pDst[0];
+ ch[1] += pDst[1];
}
+
+ pDst[0] = clamp_float(ch[0]);
+ pDst[1] = clamp_float(ch[1]);
+ pSrc += numChan;
+ pDst += 2;
+ numFrames--;
}
return true;
}
diff --git a/media/libeffects/downmix/EffectDownmix.h b/media/libeffects/downmix/EffectDownmix.h
index 679a855..1206520 100644
--- a/media/libeffects/downmix/EffectDownmix.h
+++ b/media/libeffects/downmix/EffectDownmix.h
@@ -18,88 +18,9 @@
#define ANDROID_EFFECTDOWNMIX_H_
#include <audio_effects/effect_downmix.h>
-#include <audio_utils/primitives.h>
#include <system/audio.h>
-/*------------------------------------
- * definitions
- *------------------------------------
-*/
-
-#define DOWNMIX_OUTPUT_CHANNELS AUDIO_CHANNEL_OUT_STEREO
-#define LVM_FLOAT float
-
-typedef enum {
- DOWNMIX_STATE_UNINITIALIZED,
- DOWNMIX_STATE_INITIALIZED,
- DOWNMIX_STATE_ACTIVE,
-} downmix_state_t;
-
-/* parameters for each downmixer */
-typedef struct {
- downmix_state_t state;
- downmix_type_t type;
- bool apply_volume_correction;
- uint8_t input_channel_count;
-} downmix_object_t;
-
-
-typedef struct downmix_module_s {
- const struct effect_interface_s *itfe;
- effect_config_t config;
- downmix_object_t context;
-} downmix_module_t;
-
-const uint32_t kSides = AUDIO_CHANNEL_OUT_SIDE_LEFT | AUDIO_CHANNEL_OUT_SIDE_RIGHT;
-const uint32_t kBacks = AUDIO_CHANNEL_OUT_BACK_LEFT | AUDIO_CHANNEL_OUT_BACK_RIGHT;
-const uint32_t kUnsupported =
- AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER | AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
- AUDIO_CHANNEL_OUT_TOP_CENTER |
- AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT |
- AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER |
- AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT |
- AUDIO_CHANNEL_OUT_TOP_BACK_LEFT |
- AUDIO_CHANNEL_OUT_TOP_BACK_CENTER |
- AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT;
-
-/*------------------------------------
- * Effect API
- *------------------------------------
-*/
-int32_t DownmixLib_Create(const effect_uuid_t *uuid,
- int32_t sessionId,
- int32_t ioId,
- effect_handle_t *pHandle);
-int32_t DownmixLib_Release(effect_handle_t handle);
-int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid,
- effect_descriptor_t *pDescriptor);
-
-static int Downmix_Process(effect_handle_t self,
- audio_buffer_t *inBuffer,
- audio_buffer_t *outBuffer);
-static int Downmix_Command(effect_handle_t self,
- uint32_t cmdCode,
- uint32_t cmdSize,
- void *pCmdData,
- uint32_t *replySize,
- void *pReplyData);
-static int Downmix_GetDescriptor(effect_handle_t self,
- effect_descriptor_t *pDescriptor);
-
-
-/*------------------------------------
- * internal functions
- *------------------------------------
-*/
-int Downmix_Init(downmix_module_t *pDwmModule);
-int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init);
-int Downmix_Reset(downmix_object_t *pDownmixer, bool init);
-int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue);
-int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue);
-void Downmix_foldFromQuad(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
-void Downmix_foldFrom5Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
-void Downmix_foldFrom7Point1(LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
-bool Downmix_foldGeneric(
- uint32_t mask, LVM_FLOAT *pSrc, LVM_FLOAT *pDst, size_t numFrames, bool accumulate);
+// Use the following declaration to obtain the Downmix library information.
+// extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
#endif /*ANDROID_EFFECTDOWNMIX_H_*/
diff --git a/media/libeffects/downmix/benchmark/Android.bp b/media/libeffects/downmix/benchmark/Android.bp
new file mode 100644
index 0000000..10f14e2
--- /dev/null
+++ b/media/libeffects/downmix/benchmark/Android.bp
@@ -0,0 +1,38 @@
+// Build testbench for downmix module.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_media_libeffects_downmix_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: [
+ "frameworks_av_media_libeffects_downmix_license",
+ ],
+}
+
+cc_benchmark {
+ name: "downmix_benchmark",
+ host_supported: false,
+ vendor: true,
+ include_dirs: [
+ "frameworks/av/media/libeffects/downmix",
+ ],
+ header_libs: [
+ "libaudioeffects",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libaudioutils",
+ "libdownmix",
+ ],
+ srcs: [
+ "downmix_benchmark.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
diff --git a/media/libeffects/downmix/benchmark/downmix_benchmark.cpp b/media/libeffects/downmix/benchmark/downmix_benchmark.cpp
new file mode 100644
index 0000000..ee169c2
--- /dev/null
+++ b/media/libeffects/downmix/benchmark/downmix_benchmark.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include <random>
+#include <vector>
+
+#include <audio_effects/effect_downmix.h>
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/Statistics.h>
+#include <benchmark/benchmark.h>
+#include <log/log.h>
+#include <system/audio.h>
+
+#include "EffectDownmix.h"
+
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+
+static constexpr audio_channel_mask_t kChannelPositionMasks[] = {
+ AUDIO_CHANNEL_OUT_FRONT_LEFT,
+ AUDIO_CHANNEL_OUT_FRONT_CENTER,
+ AUDIO_CHANNEL_OUT_STEREO,
+ AUDIO_CHANNEL_OUT_2POINT1,
+ AUDIO_CHANNEL_OUT_2POINT0POINT2,
+ AUDIO_CHANNEL_OUT_QUAD,
+ AUDIO_CHANNEL_OUT_QUAD_BACK,
+ AUDIO_CHANNEL_OUT_QUAD_SIDE,
+ AUDIO_CHANNEL_OUT_SURROUND,
+ AUDIO_CHANNEL_OUT_2POINT1POINT2,
+ AUDIO_CHANNEL_OUT_3POINT0POINT2,
+ AUDIO_CHANNEL_OUT_PENTA,
+ AUDIO_CHANNEL_OUT_3POINT1POINT2,
+ AUDIO_CHANNEL_OUT_5POINT1,
+ AUDIO_CHANNEL_OUT_5POINT1_BACK,
+ AUDIO_CHANNEL_OUT_5POINT1_SIDE,
+ AUDIO_CHANNEL_OUT_6POINT1,
+ AUDIO_CHANNEL_OUT_5POINT1POINT2,
+ AUDIO_CHANNEL_OUT_7POINT1,
+ AUDIO_CHANNEL_OUT_5POINT1POINT4,
+ AUDIO_CHANNEL_OUT_7POINT1POINT2,
+ AUDIO_CHANNEL_OUT_7POINT1POINT4,
+ AUDIO_CHANNEL_OUT_13POINT_360RA,
+ AUDIO_CHANNEL_OUT_22POINT2,
+};
+
+static constexpr effect_uuid_t downmix_uuid = {
+ 0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
+
+static constexpr size_t kFrameCount = 1000;
+
+/*
+Pixel 3XL
+downmix_benchmark:
+ #BM_Downmix/0 4723 ns 4708 ns 148694
+ #BM_Downmix/1 4717 ns 4702 ns 148873
+ #BM_Downmix/2 4803 ns 4788 ns 145893
+ #BM_Downmix/3 5056 ns 5041 ns 139110
+ #BM_Downmix/4 4710 ns 4696 ns 149625
+ #BM_Downmix/5 1514 ns 1509 ns 463694
+ #BM_Downmix/6 1513 ns 1509 ns 463451
+ #BM_Downmix/7 1516 ns 1511 ns 463899
+ #BM_Downmix/8 4445 ns 4431 ns 157831
+ #BM_Downmix/9 5081 ns 5065 ns 138412
+ #BM_Downmix/10 4354 ns 4341 ns 161247
+ #BM_Downmix/11 4411 ns 4397 ns 158893
+ #BM_Downmix/12 4434 ns 4420 ns 157992
+ #BM_Downmix/13 4845 ns 4830 ns 144873
+ #BM_Downmix/14 4851 ns 4835 ns 144954
+ #BM_Downmix/15 4884 ns 4870 ns 144233
+ #BM_Downmix/16 5832 ns 5813 ns 120565
+ #BM_Downmix/17 5241 ns 5224 ns 133927
+ #BM_Downmix/18 5044 ns 5028 ns 139131
+ #BM_Downmix/19 5244 ns 5227 ns 132315
+ #BM_Downmix/20 5943 ns 5923 ns 117759
+ #BM_Downmix/21 5990 ns 5971 ns 117263
+ #BM_Downmix/22 4468 ns 4454 ns 156689
+ #BM_Downmix/23 7306 ns 7286 ns 95911
+--
+downmix_benchmark: (generic fold)
+ #BM_Downmix/0 4722 ns 4707 ns 149847
+ #BM_Downmix/1 4714 ns 4698 ns 148748
+ #BM_Downmix/2 4794 ns 4779 ns 145661
+ #BM_Downmix/3 5053 ns 5035 ns 139172
+ #BM_Downmix/4 4695 ns 4678 ns 149762
+ #BM_Downmix/5 4381 ns 4368 ns 159675
+ #BM_Downmix/6 4387 ns 4373 ns 160267
+ #BM_Downmix/7 4732 ns 4717 ns 148514
+ #BM_Downmix/8 4430 ns 4415 ns 158133
+ #BM_Downmix/9 5101 ns 5084 ns 138353
+ #BM_Downmix/10 4356 ns 4343 ns 160821
+ #BM_Downmix/11 4397 ns 4383 ns 159995
+ #BM_Downmix/12 4438 ns 4424 ns 158117
+ #BM_Downmix/13 5243 ns 5226 ns 133863
+ #BM_Downmix/14 5259 ns 5242 ns 131855
+ #BM_Downmix/15 5245 ns 5228 ns 133686
+ #BM_Downmix/16 5829 ns 5809 ns 120543
+ #BM_Downmix/17 5245 ns 5228 ns 133533
+ #BM_Downmix/18 5935 ns 5916 ns 118282
+ #BM_Downmix/19 5263 ns 5245 ns 133657
+ #BM_Downmix/20 5998 ns 5978 ns 114693
+ #BM_Downmix/21 5989 ns 5969 ns 117450
+ #BM_Downmix/22 4442 ns 4431 ns 157913
+ #BM_Downmix/23 7309 ns 7290 ns 95797
+*/
+
+static void BM_Downmix(benchmark::State& state) {
+ const audio_channel_mask_t channelMask = kChannelPositionMasks[state.range(0)];
+ const size_t channelCount = audio_channel_count_from_out_mask(channelMask);
+ const int sampleRate = 48000;
+
+ // Initialize input buffer with deterministic pseudo-random values
+ std::minstd_rand gen(channelMask);
+ std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+ std::vector<float> input(kFrameCount * channelCount);
+ std::vector<float> output(kFrameCount * 2);
+ for (auto& in : input) {
+ in = dis(gen);
+ }
+ effect_handle_t effectHandle = nullptr;
+ if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
+ &downmix_uuid, 1, 1, &effectHandle);
+ status != 0) {
+ ALOGE("create_effect returned an error = %d\n", status);
+ return;
+ }
+
+ effect_config_t config{};
+ config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ config.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+ config.inputCfg.bufferProvider.getBuffer = nullptr;
+ config.inputCfg.bufferProvider.releaseBuffer = nullptr;
+ config.inputCfg.bufferProvider.cookie = nullptr;
+ config.inputCfg.mask = EFFECT_CONFIG_ALL;
+
+ config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+ config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+ config.outputCfg.bufferProvider.getBuffer = nullptr;
+ config.outputCfg.bufferProvider.releaseBuffer = nullptr;
+ config.outputCfg.bufferProvider.cookie = nullptr;
+ config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ config.inputCfg.samplingRate = sampleRate;
+ config.inputCfg.channels = channelMask;
+
+ config.outputCfg.samplingRate = sampleRate;
+ config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; // output always stereo
+
+ int reply = 0;
+ uint32_t replySize = sizeof(reply);
+ if (int status = (*effectHandle)
+ ->command(effectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
+ &config, &replySize, &reply);
+ status != 0) {
+ ALOGE("command returned an error = %d\n", status);
+ return;
+ }
+
+ if (int status = (*effectHandle)
+ ->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
+ status != 0) {
+ ALOGE("Command enable call returned error %d\n", reply);
+ return;
+ }
+
+ // Run the test
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(input.data());
+ benchmark::DoNotOptimize(output.data());
+
+ audio_buffer_t inBuffer = {.frameCount = kFrameCount, .f32 = input.data()};
+ audio_buffer_t outBuffer = {.frameCount = kFrameCount, .f32 = output.data()};
+ (*effectHandle)->process(effectHandle, &inBuffer, &outBuffer);
+
+ benchmark::ClobberMemory();
+ }
+
+ state.SetComplexityN(state.range(0));
+
+ if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
+ ALOGE("release_effect returned an error = %d\n", status);
+ return;
+ }
+}
+
+static void DownmixArgs(benchmark::internal::Benchmark* b) {
+ for (int i = 0; i < (int)std::size(kChannelPositionMasks); i++) {
+ b->Args({i});
+ }
+}
+
+BENCHMARK(BM_Downmix)->Apply(DownmixArgs);
+
+BENCHMARK_MAIN();
diff --git a/media/libeffects/downmix/tests/Android.bp b/media/libeffects/downmix/tests/Android.bp
index 4077312..4940117 100644
--- a/media/libeffects/downmix/tests/Android.bp
+++ b/media/libeffects/downmix/tests/Android.bp
@@ -10,6 +10,43 @@
],
}
+// This is a gtest unit test.
+//
+// Use "atest downmix_tests" to run.
+cc_test {
+ name:"downmix_tests",
+ gtest: true,
+ host_supported: true,
+ vendor: true,
+ include_dirs: [
+ "frameworks/av/media/libeffects/downmix",
+ ],
+ header_libs: [
+ "libaudioeffects",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libaudioutils",
+ "libdownmix",
+ ],
+ srcs: [
+ "downmix_tests.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
+
+// This is a test application which generates downmixed files for regression
+// analysis.
+//
+// See build_and_run_all_unit_tests.sh for a test script that uses this
+// test application and outputs then compares files in a local directory
+// on device (/data/local/tmp/downmixtest/).
cc_test {
name:"downmixtest",
host_supported: false,
diff --git a/media/libeffects/downmix/tests/downmix_tests.cpp b/media/libeffects/downmix/tests/downmix_tests.cpp
new file mode 100644
index 0000000..d4b7a3a
--- /dev/null
+++ b/media/libeffects/downmix/tests/downmix_tests.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <vector>
+
+#include "EffectDownmix.h"
+
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/Statistics.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+static constexpr audio_channel_mask_t kChannelPositionMasks[] = {
+ AUDIO_CHANNEL_OUT_FRONT_LEFT, // Legacy: the downmix effect treats MONO as FRONT_LEFT only.
+ // The AudioMixer interprets MONO as a special case requiring
+ // channel replication, bypassing the downmix effect.
+ AUDIO_CHANNEL_OUT_FRONT_CENTER,
+ AUDIO_CHANNEL_OUT_STEREO,
+ AUDIO_CHANNEL_OUT_2POINT1,
+ AUDIO_CHANNEL_OUT_2POINT0POINT2,
+ AUDIO_CHANNEL_OUT_QUAD,
+ AUDIO_CHANNEL_OUT_QUAD_BACK,
+ AUDIO_CHANNEL_OUT_QUAD_SIDE,
+ AUDIO_CHANNEL_OUT_SURROUND,
+ AUDIO_CHANNEL_OUT_2POINT1POINT2,
+ AUDIO_CHANNEL_OUT_3POINT0POINT2,
+ AUDIO_CHANNEL_OUT_PENTA,
+ AUDIO_CHANNEL_OUT_3POINT1POINT2,
+ AUDIO_CHANNEL_OUT_5POINT1,
+ AUDIO_CHANNEL_OUT_5POINT1_BACK,
+ AUDIO_CHANNEL_OUT_5POINT1_SIDE,
+ AUDIO_CHANNEL_OUT_6POINT1,
+ AUDIO_CHANNEL_OUT_5POINT1POINT2,
+ AUDIO_CHANNEL_OUT_7POINT1,
+ AUDIO_CHANNEL_OUT_5POINT1POINT4,
+ AUDIO_CHANNEL_OUT_7POINT1POINT2,
+ AUDIO_CHANNEL_OUT_7POINT1POINT4,
+ AUDIO_CHANNEL_OUT_13POINT_360RA,
+ AUDIO_CHANNEL_OUT_22POINT2,
+};
+
+static constexpr audio_channel_mask_t kConsideredChannels =
+ (audio_channel_mask_t)(AUDIO_CHANNEL_OUT_7POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER);
+
+// Downmix doesn't change with sample rate
+static constexpr size_t kSampleRates[] = {
+ 48000,
+};
+
+// Our near expectation is 16x the bit that doesn't fit the mantissa.
+// this works so long as we add values close in exponent with each other
+// realizing that errors accumulate as the sqrt of N (random walk, lln, etc).
+#define EXPECT_NEAR_EPSILON(e, v) EXPECT_NEAR((e), (v), \
+ abs((e) * std::numeric_limits<std::decay_t<decltype(e)>>::epsilon() * 8))
+
+template<typename T>
+static auto channelStatistics(const std::vector<T>& input, size_t channels) {
+ std::vector<android::audio_utils::Statistics<T>> result(channels);
+ const size_t frames = input.size() / channels;
+ if (frames > 0) {
+ const float *fptr = input.data();
+ for (size_t i = 0; i < frames; ++i) {
+ for (size_t j = 0; j < channels; ++j) {
+ result[j].add(*fptr++);
+ }
+ }
+ }
+ return result;
+}
+
+using DownmixParam = std::tuple<int /* sample rate */, int /* channel mask */>;
+class DownmixTest : public ::testing::TestWithParam<DownmixParam> {
+public:
+ static constexpr effect_uuid_t downmix_uuid_ = {
+ 0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
+ static constexpr size_t FRAME_LENGTH = 256;
+
+ void testBalance(int sampleRate, audio_channel_mask_t channelMask) {
+ using namespace ::android::audio_utils::channels;
+
+ size_t frames = 100;
+ unsigned outChannels = 2;
+ unsigned inChannels = audio_channel_count_from_out_mask(channelMask);
+ std::vector<float> input(frames * inChannels);
+ std::vector<float> output(frames * outChannels);
+
+ double savedPower[32][2]{};
+ for (unsigned i = 0, channel = channelMask; channel != 0; ++i) {
+ const int index = __builtin_ctz(channel);
+ ASSERT_LT(index, FCC_24);
+ const int pairIndex = pairIdxFromChannelIdx(index);
+ const AUDIO_GEOMETRY_SIDE side = sideFromChannelIdx(index);
+ const int channelBit = 1 << index;
+ channel &= ~channelBit;
+
+ // Generate a +1, -1 alternating stream in one channel, which has variance 1.
+ auto indata = input.data();
+ for (unsigned j = 0; j < frames; ++j) {
+ for (unsigned k = 0; k < inChannels; ++k) {
+ *indata++ = (k == i) ? (j & 1 ? -1 : 1) : 0;
+ }
+ }
+ run(sampleRate, channelMask, input, output, frames);
+
+ auto stats = channelStatistics(output, 2 /* channels */);
+ // printf("power: %s %s\n", stats[0].toString().c_str(), stats[1].toString().c_str());
+ double power[2] = { stats[0].getVariance(), stats[1].getVariance() };
+
+ // Check symmetric power for pair channels on exchange of left/right position.
+ // to do this, we save previous power measurements.
+ if (pairIndex >= 0 && pairIndex < index) {
+ EXPECT_NEAR_EPSILON(power[0], savedPower[pairIndex][1]);
+ EXPECT_NEAR_EPSILON(power[1], savedPower[pairIndex][0]);
+ }
+ savedPower[index][0] = power[0];
+ savedPower[index][1] = power[1];
+
+ // Confirm exactly the mix amount prescribed by the existing downmix effect.
+ // For future changes to the downmix effect, the nearness needs to be relaxed
+ // to compare behavior S or earlier.
+ if ((channelBit & kConsideredChannels) == 0) {
+ // for channels not considered, expect 0 power for legacy downmix
+ EXPECT_EQ(0.f, power[0]);
+ EXPECT_EQ(0.f, power[1]);
+ continue;
+ }
+ constexpr float POWER_TOLERANCE = 0.01; // for variance sum error.
+ switch (side) {
+ case AUDIO_GEOMETRY_SIDE_LEFT:
+ EXPECT_NEAR(0.25f, power[0], POWER_TOLERANCE);
+ EXPECT_EQ(0.f, power[1]);
+ break;
+ case AUDIO_GEOMETRY_SIDE_RIGHT:
+ EXPECT_EQ(0.f, power[0]);
+ EXPECT_NEAR(0.25f, power[1], POWER_TOLERANCE);
+ break;
+ case AUDIO_GEOMETRY_SIDE_CENTER:
+ EXPECT_NEAR(0.125f, power[0], POWER_TOLERANCE);
+ EXPECT_NEAR(0.125f, power[1], POWER_TOLERANCE);
+ EXPECT_NEAR_EPSILON(power[0], power[1]);
+ break;
+ }
+ }
+ }
+
+ void run(int sampleRate, audio_channel_mask_t channelMask,
+ std::vector<float>& input, std::vector<float>& output, size_t frames) {
+ reconfig(sampleRate, channelMask);
+
+ ASSERT_EQ(frames * inputChannelCount_, input.size());
+ ASSERT_EQ(frames * outputChannelCount_, output.size());
+
+ const int32_t sessionId = 0;
+ const int32_t ioId = 0;
+ int32_t err = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
+ &downmix_uuid_, sessionId, ioId, &handle_);
+ ASSERT_EQ(0, err);
+
+ const struct effect_interface_s * const downmixApi = *handle_;
+ int32_t reply = 0;
+ uint32_t replySize = (uint32_t)sizeof(reply);
+ err = (downmixApi->command)(
+ handle_, EFFECT_CMD_SET_CONFIG,
+ sizeof(effect_config_t), &config_, &replySize, &reply);
+ ASSERT_EQ(0, err);
+ err = (downmixApi->command)(
+ handle_, EFFECT_CMD_ENABLE,
+ 0, nullptr, &replySize, &reply);
+ ASSERT_EQ(0, err);
+
+ process(input, output, frames);
+ err = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(handle_);
+ ASSERT_EQ(0, err);
+ }
+
+private:
+ void reconfig(int sampleRate, audio_channel_mask_t channelMask) {
+ config_.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ config_.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+ config_.inputCfg.bufferProvider.getBuffer = nullptr;
+ config_.inputCfg.bufferProvider.releaseBuffer = nullptr;
+ config_.inputCfg.bufferProvider.cookie = nullptr;
+ config_.inputCfg.mask = EFFECT_CONFIG_ALL;
+
+ config_.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+ config_.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+ config_.outputCfg.bufferProvider.getBuffer = nullptr;
+ config_.outputCfg.bufferProvider.releaseBuffer = nullptr;
+ config_.outputCfg.bufferProvider.cookie = nullptr;
+ config_.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ config_.inputCfg.samplingRate = sampleRate;
+ config_.inputCfg.channels = channelMask;
+ inputChannelCount_ = audio_channel_count_from_out_mask(config_.inputCfg.channels);
+
+ config_.outputCfg.samplingRate = sampleRate;
+ config_.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; // output always stereo
+ outputChannelCount_ = audio_channel_count_from_out_mask(config_.outputCfg.channels);
+ }
+
+ void process(std::vector<float> &input, std::vector<float> &output, size_t frames) const {
+ const struct effect_interface_s * const downmixApi = *handle_;
+
+ for (size_t pos = 0; pos < frames;) {
+ const size_t transfer = std::min(frames - pos, FRAME_LENGTH);
+ audio_buffer_t inbuffer{.frameCount = transfer,
+ .f32 = input.data() + pos * inputChannelCount_};
+ audio_buffer_t outbuffer{.frameCount = transfer,
+ .f32 = output.data() + pos * outputChannelCount_};
+ const int32_t err = (downmixApi->process)(handle_, &inbuffer, &outbuffer);
+ ASSERT_EQ(0, err);
+ pos += transfer;
+ }
+ }
+
+ effect_handle_t handle_{};
+ effect_config_t config_{};
+ int outputChannelCount_{};
+ int inputChannelCount_{};
+};
+
+TEST_P(DownmixTest, basic) {
+ testBalance(kSampleRates[std::get<0>(GetParam())],
+ kChannelPositionMasks[std::get<1>(GetParam())]);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DownmixTestAll, DownmixTest,
+ ::testing::Combine(
+ ::testing::Range(0, (int)std::size(kSampleRates)),
+ ::testing::Range(0, (int)std::size(kChannelPositionMasks))
+ ));
+
+int main(int argc, /* const */ char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ return status;
+}
diff --git a/media/libeffects/downmix/tests/downmixtest.cpp b/media/libeffects/downmix/tests/downmixtest.cpp
index 71f83e5..4076320 100644
--- a/media/libeffects/downmix/tests/downmixtest.cpp
+++ b/media/libeffects/downmix/tests/downmixtest.cpp
@@ -29,7 +29,6 @@
#define MAX_NUM_CHANNELS 8
struct downmix_cntxt_s {
- effect_descriptor_t desc;
effect_handle_t handle;
effect_config_t config;
@@ -87,13 +86,12 @@
}
int32_t DownmixConfiureAndEnable(downmix_cntxt_s *pDescriptor) {
- effect_handle_t *effectHandle = &pDescriptor->handle;
- downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
- const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
+ effect_handle_t effectHandle = pDescriptor->handle;
+ const struct effect_interface_s *Downmix_api = *effectHandle;
int32_t err = 0;
uint32_t replySize = (uint32_t)sizeof(err);
- err = (Downmix_api->command)(*effectHandle, EFFECT_CMD_SET_CONFIG,
+ err = (Downmix_api->command)(effectHandle, EFFECT_CMD_SET_CONFIG,
sizeof(effect_config_t), &(pDescriptor->config),
&replySize, &err);
if (err != 0) {
@@ -101,7 +99,7 @@
return err;
}
- err = ((Downmix_api->command))(*effectHandle, EFFECT_CMD_ENABLE, 0, nullptr,
+ err = ((Downmix_api->command))(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr,
&replySize, &err);
if (err != 0) {
ALOGE("Downmix command to enable effect returned an error %d", err);
@@ -112,9 +110,8 @@
int32_t DownmixExecute(downmix_cntxt_s *pDescriptor, FILE *finp,
FILE *fout) {
- effect_handle_t *effectHandle = &pDescriptor->handle;
- downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
- const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
+ effect_handle_t effectHandle = pDescriptor->handle;
+ const struct effect_interface_s *Downmix_api = *effectHandle;
const int numFileChannels = pDescriptor->numFileChannels;
const int numProcessChannels = pDescriptor->numProcessChannels;
@@ -150,7 +147,7 @@
memcpy_to_float_from_i16(inFloat.data(), inS16.data(),
FRAME_LENGTH * numProcessChannels);
- const int32_t err = (Downmix_api->process)(*effectHandle, pinbuf, poutbuf);
+ const int32_t err = (Downmix_api->process)(effectHandle, pinbuf, poutbuf);
if (err != 0) {
ALOGE("DownmixProcess returned an error %d", err);
return -1;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 3562b00..00f423c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -312,6 +312,27 @@
return NO_ERROR;
}
+status_t AudioFlinger::updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs) {
+ Mutex::Autolock _l(mLock);
+ for (const auto& [trackId, secondaryOutputs] : trackSecondaryOutputs) {
+ size_t i = 0;
+ for (; i < mPlaybackThreads.size(); ++i) {
+ PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+ Mutex::Autolock _tl(thread->mLock);
+ sp<PlaybackThread::Track> track = thread->getTrackById_l(trackId);
+ if (track != nullptr) {
+ ALOGD("%s trackId: %u", __func__, trackId);
+ updateSecondaryOutputsForTrack_l(track.get(), thread, secondaryOutputs);
+ break;
+ }
+ }
+ ALOGW_IF(i >= mPlaybackThreads.size(),
+ "%s cannot find track with id %u", __func__, trackId);
+ }
+ return NO_ERROR;
+}
+
// getDefaultVibratorInfo_l must be called with AudioFlinger lock held.
const media::AudioVibratorInfo* AudioFlinger::getDefaultVibratorInfo_l() {
if (mAudioVibratorInfos.empty()) {
@@ -944,88 +965,7 @@
// Connect secondary outputs. Failure on a secondary output must not imped the primary
// Any secondary output setup failure will lead to a desync between the AP and AF until
// the track is destroyed.
- TeePatches teePatches;
- for (audio_io_handle_t secondaryOutput : secondaryOutputs) {
- PlaybackThread *secondaryThread = checkPlaybackThread_l(secondaryOutput);
- if (secondaryThread == NULL) {
- ALOGE("no playback thread found for secondary output %d", output.outputId);
- continue;
- }
-
- size_t sourceFrameCount = thread->frameCount() * output.sampleRate
- / thread->sampleRate();
- size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate
- / secondaryThread->sampleRate();
- // If the secondary output has just been opened, the first secondaryThread write
- // will not block as it will fill the empty startup buffer of the HAL,
- // so a second sink buffer needs to be ready for the immediate next blocking write.
- // Additionally, have a margin of one main thread buffer as the scheduling jitter
- // can reorder the writes (eg if thread A&B have the same write intervale,
- // the scheduler could schedule AB...BA)
- size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
- // Total secondary output buffer must be at least as the read frames plus
- // the margin of a few buffers on both sides in case the
- // threads scheduling has some jitter.
- // That value should not impact latency as the secondary track is started before
- // its buffer is full, see frameCountToBeReady.
- size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
- // The frameCount should also not be smaller than the secondary thread min frame
- // count
- size_t minFrameCount = AudioSystem::calculateMinFrameCount(
- [&] { Mutex::Autolock _l(secondaryThread->mLock);
- return secondaryThread->latency_l(); }(),
- secondaryThread->mNormalFrameCount,
- secondaryThread->mSampleRate,
- output.sampleRate,
- input.speed);
- frameCount = std::max(frameCount, minFrameCount);
-
- using namespace std::chrono_literals;
- auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask);
- sp patchRecord = new RecordThread::PatchRecord(nullptr /* thread */,
- output.sampleRate,
- inChannelMask,
- input.config.format,
- frameCount,
- NULL /* buffer */,
- (size_t)0 /* bufferSize */,
- AUDIO_INPUT_FLAG_DIRECT,
- 0ns /* timeout */);
- status_t status = patchRecord->initCheck();
- if (status != NO_ERROR) {
- ALOGE("Secondary output patchRecord init failed: %d", status);
- continue;
- }
-
- // TODO: We could check compatibility of the secondaryThread with the PatchTrack
- // for fast usage: thread has fast mixer, sample rate matches, etc.;
- // for now, we exclude fast tracks by removing the Fast flag.
- const audio_output_flags_t outputFlags =
- (audio_output_flags_t)(output.flags & ~AUDIO_OUTPUT_FLAG_FAST);
- sp patchTrack = new PlaybackThread::PatchTrack(secondaryThread,
- streamType,
- output.sampleRate,
- input.config.channel_mask,
- input.config.format,
- frameCount,
- patchRecord->buffer(),
- patchRecord->bufferSize(),
- outputFlags,
- 0ns /* timeout */,
- frameCountToBeReady);
- status = patchTrack->initCheck();
- if (status != NO_ERROR) {
- ALOGE("Secondary output patchTrack init failed: %d", status);
- continue;
- }
- teePatches.push_back({patchRecord, patchTrack});
- secondaryThread->addPatchTrack(patchTrack);
- // In case the downstream patchTrack on the secondaryThread temporarily outlives
- // our created track, ensure the corresponding patchRecord is still alive.
- patchTrack->setPeerProxy(patchRecord, true /* holdReference */);
- patchRecord->setPeerProxy(patchTrack, false /* holdReference */);
- }
- track->setTeePatches(std::move(teePatches));
+ updateSecondaryOutputsForTrack_l(track.get(), thread, secondaryOutputs);
}
// move effect chain to this output thread if an effect on same session was waiting
@@ -3441,6 +3381,94 @@
return nullptr;
}
+void AudioFlinger::updateSecondaryOutputsForTrack_l(
+ PlaybackThread::Track* track,
+ PlaybackThread* thread,
+ const std::vector<audio_io_handle_t> &secondaryOutputs) const {
+ TeePatches teePatches;
+ for (audio_io_handle_t secondaryOutput : secondaryOutputs) {
+ PlaybackThread *secondaryThread = checkPlaybackThread_l(secondaryOutput);
+ if (secondaryThread == nullptr) {
+ ALOGE("no playback thread found for secondary output %d", thread->id());
+ continue;
+ }
+
+ size_t sourceFrameCount = thread->frameCount() * track->sampleRate()
+ / thread->sampleRate();
+ size_t sinkFrameCount = secondaryThread->frameCount() * track->sampleRate()
+ / secondaryThread->sampleRate();
+ // If the secondary output has just been opened, the first secondaryThread write
+ // will not block as it will fill the empty startup buffer of the HAL,
+ // so a second sink buffer needs to be ready for the immediate next blocking write.
+ // Additionally, have a margin of one main thread buffer as the scheduling jitter
+ // can reorder the writes (eg if thread A&B have the same write intervale,
+ // the scheduler could schedule AB...BA)
+ size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
+ // Total secondary output buffer must be at least as the read frames plus
+ // the margin of a few buffers on both sides in case the
+ // threads scheduling has some jitter.
+ // That value should not impact latency as the secondary track is started before
+ // its buffer is full, see frameCountToBeReady.
+ size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
+ // The frameCount should also not be smaller than the secondary thread min frame
+ // count
+ size_t minFrameCount = AudioSystem::calculateMinFrameCount(
+ [&] { Mutex::Autolock _l(secondaryThread->mLock);
+ return secondaryThread->latency_l(); }(),
+ secondaryThread->mNormalFrameCount,
+ secondaryThread->mSampleRate,
+ track->sampleRate(),
+ track->getSpeed());
+ frameCount = std::max(frameCount, minFrameCount);
+
+ using namespace std::chrono_literals;
+ auto inChannelMask = audio_channel_mask_out_to_in(track->channelMask());
+ sp patchRecord = new RecordThread::PatchRecord(nullptr /* thread */,
+ track->sampleRate(),
+ inChannelMask,
+ track->format(),
+ frameCount,
+ nullptr /* buffer */,
+ (size_t)0 /* bufferSize */,
+ AUDIO_INPUT_FLAG_DIRECT,
+ 0ns /* timeout */);
+ status_t status = patchRecord->initCheck();
+ if (status != NO_ERROR) {
+ ALOGE("Secondary output patchRecord init failed: %d", status);
+ continue;
+ }
+
+ // TODO: We could check compatibility of the secondaryThread with the PatchTrack
+ // for fast usage: thread has fast mixer, sample rate matches, etc.;
+ // for now, we exclude fast tracks by removing the Fast flag.
+ const audio_output_flags_t outputFlags =
+ (audio_output_flags_t)(track->getOutputFlags() & ~AUDIO_OUTPUT_FLAG_FAST);
+ sp patchTrack = new PlaybackThread::PatchTrack(secondaryThread,
+ track->streamType(),
+ track->sampleRate(),
+ track->channelMask(),
+ track->format(),
+ frameCount,
+ patchRecord->buffer(),
+ patchRecord->bufferSize(),
+ outputFlags,
+ 0ns /* timeout */,
+ frameCountToBeReady);
+ status = patchTrack->initCheck();
+ if (status != NO_ERROR) {
+ ALOGE("Secondary output patchTrack init failed: %d", status);
+ continue;
+ }
+ teePatches.push_back({patchRecord, patchTrack});
+ secondaryThread->addPatchTrack(patchTrack);
+ // In case the downstream patchTrack on the secondaryThread temporarily outlives
+ // our created track, ensure the corresponding patchRecord is still alive.
+ patchTrack->setPeerProxy(patchRecord, true /* holdReference */);
+ patchRecord->setPeerProxy(patchTrack, false /* holdReference */);
+ }
+ track->setTeePatches(std::move(teePatches));
+}
+
sp<AudioFlinger::SyncEvent> AudioFlinger::createSyncEvent(AudioSystem::sync_event_t type,
audio_session_t triggerSession,
audio_session_t listenerSession,
@@ -4170,7 +4198,8 @@
case TransactionCode::SET_LOW_RAM_DEVICE:
case TransactionCode::SYSTEM_READY:
case TransactionCode::SET_AUDIO_HAL_PIDS:
- case TransactionCode::SET_VIBRATOR_INFOS: {
+ case TransactionCode::SET_VIBRATOR_INFOS:
+ case TransactionCode::UPDATE_SECONDARY_OUTPUTS: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 4b03d10..b12f52e 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -272,6 +272,9 @@
virtual status_t setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos);
+ virtual status_t updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs);
+
status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
const std::function<status_t()>& delegate) override;
@@ -775,6 +778,11 @@
ThreadBase *hapticPlaybackThread_l() const;
+ void updateSecondaryOutputsForTrack_l(
+ PlaybackThread::Track* track,
+ PlaybackThread* thread,
+ const std::vector<audio_io_handle_t>& secondaryOutputs) const;
+
void removeClient_l(pid_t pid);
void removeNotificationClient(pid_t pid);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 0af4c7b..30a2432 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -81,7 +81,8 @@
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
/** default behaviour is to start when there are as many frames
* ready as possible (aka. Buffer is full). */
- size_t frameCountToBeReady = SIZE_MAX);
+ size_t frameCountToBeReady = SIZE_MAX,
+ float speed = 1.0f);
virtual ~Track();
virtual status_t initCheck() const;
@@ -183,6 +184,9 @@
mAudioTrackServerProxy->getUnderrunFrames());
}
}
+
+ audio_output_flags_t getOutputFlags() const { return mFlags; }
+ float getSpeed() const { return mSpeed; }
protected:
// for numerous
friend class PlaybackThread;
@@ -311,6 +315,7 @@
bool mPauseHwPending = false; // direct/offload track request for thread pause
audio_output_flags_t mFlags;
TeePatches mTeePatches;
+ const float mSpeed;
}; // end of Track
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d878611..25a19a2 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2425,7 +2425,7 @@
channelMask, frameCount,
nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
sessionId, creatorPid, identity, trackFlags, TrackBase::TYPE_DEFAULT,
- portId, SIZE_MAX /*frameCountToBeReady*/);
+ portId, SIZE_MAX /*frameCountToBeReady*/, speed);
lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
if (lStatus != NO_ERROR) {
@@ -3321,6 +3321,17 @@
invalidateTracks_l(streamType);
}
+// getTrackById_l must be called with holding thread lock
+AudioFlinger::PlaybackThread::Track* AudioFlinger::PlaybackThread::getTrackById_l(
+ audio_port_handle_t trackPortId) {
+ for (size_t i = 0; i < mTracks.size(); i++) {
+ if (mTracks[i]->portId() == trackPortId) {
+ return mTracks[i].get();
+ }
+ }
+ return nullptr;
+}
+
status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
{
audio_session_t session = chain->sessionId();
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 17acb16..d4fb995 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1013,6 +1013,8 @@
mDownStreamPatch = *patch;
}
+ PlaybackThread::Track* getTrackById_l(audio_port_handle_t trackId);
+
protected:
// updated by readOutputParameters_l()
size_t mNormalFrameCount; // normal mixer and effects
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8be7c86..09e5ec5 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -624,7 +624,8 @@
audio_output_flags_t flags,
track_type type,
audio_port_handle_t portId,
- size_t frameCountToBeReady)
+ size_t frameCountToBeReady,
+ float speed)
: TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
@@ -658,7 +659,8 @@
mFinalVolume(0.f),
mResumeToStopping(false),
mFlushHwPending(false),
- mFlags(flags)
+ mFlags(flags),
+ mSpeed(speed)
{
// client == 0 implies sharedBuffer == 0
ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
@@ -1404,6 +1406,10 @@
void AudioFlinger::PlaybackThread::Track::setTeePatches(TeePatches teePatches) {
forEachTeePatchTrack([](auto patchTrack) { patchTrack->destroy(); });
mTeePatches = std::move(teePatches);
+ if (mState == TrackBase::ACTIVE || mState == TrackBase::RESUMING ||
+ mState == TrackBase::STOPPING_1) {
+ forEachTeePatchTrack([](auto patchTrack) { patchTrack->start(); });
+ }
}
status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 5f052a5..a904321 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_AUDIOPOLICY_INTERFACE_H
#define ANDROID_AUDIOPOLICY_INTERFACE_H
+#include <media/AudioCommonTypes.h>
#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
@@ -453,6 +454,9 @@
virtual void setSoundTriggerCaptureState(bool active) = 0;
virtual status_t getAudioPort(struct audio_port_v7 *port) = 0;
+
+ virtual status_t updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs) = 0;
};
// These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 59876c6..74b3405 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -109,6 +109,9 @@
const std::vector<wp<SwAudioOutputDescriptor>>& getSecondaryOutputs() const {
return mSecondaryOutputs;
};
+ void setSecondaryOutputs(std::vector<wp<SwAudioOutputDescriptor>>&& secondaryOutputs) {
+ mSecondaryOutputs = std::move(secondaryOutputs);
+ }
VolumeSource volumeSource() const { return mVolumeSource; }
const sp<AudioPolicyMix> getPrimaryMix() const {
return mPrimaryMix.promote();
@@ -143,7 +146,7 @@
const product_strategy_t mStrategy;
const VolumeSource mVolumeSource;
const audio_output_flags_t mFlags;
- const std::vector<wp<SwAudioOutputDescriptor>> mSecondaryOutputs;
+ std::vector<wp<SwAudioOutputDescriptor>> mSecondaryOutputs;
const wp<AudioPolicyMix> mPrimaryMix;
/**
* required for duplicating thread, prevent from removing active client from an output
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index b5885c0..76c35c1 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -200,6 +200,11 @@
#
ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
+ #
+ # Reaching 32 bit limit for inclusive criterion out devices: removing
+ #
+ ignored_output_device_values = ['BleSpeaker', 'BleHeadset']
+
criteria_pattern = re.compile(
r"\s*V\((?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*,\s*" \
@@ -235,7 +240,9 @@
if criterion_name == "OutputDevicesMaskType":
if criterion_literal == "Default":
criterion_numerical_value = str(int("0x40000000", 0))
-
+ if criterion_literal in ignored_output_device_values:
+ logging.info("OutputDevicesMaskType skipping {}".format(criterion_literal))
+ continue
try:
string_int = int(criterion_numerical_value, 0)
except ValueError:
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7185435..c8ddbc6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -31,6 +31,7 @@
#include <algorithm>
#include <inttypes.h>
+#include <map>
#include <math.h>
#include <set>
#include <unordered_set>
@@ -5694,6 +5695,7 @@
void AudioPolicyManager::checkSecondaryOutputs() {
std::set<audio_stream_type_t> streamsToInvalidate;
+ TrackSecondaryOutputsMap trackSecondaryOutputs;
for (size_t i = 0; i < mOutputs.size(); i++) {
const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
@@ -5710,16 +5712,28 @@
}
}
- if (status != OK ||
- !std::equal(client->getSecondaryOutputs().begin(),
- client->getSecondaryOutputs().end(),
- secondaryDescs.begin(), secondaryDescs.end())) {
+ if (status != OK) {
streamsToInvalidate.insert(client->stream());
+ } else if (!std::equal(
+ client->getSecondaryOutputs().begin(),
+ client->getSecondaryOutputs().end(),
+ secondaryDescs.begin(), secondaryDescs.end())) {
+ std::vector<wp<SwAudioOutputDescriptor>> weakSecondaryDescs;
+ std::vector<audio_io_handle_t> secondaryOutputIds;
+ for (const auto& secondaryDesc : secondaryDescs) {
+ secondaryOutputIds.push_back(secondaryDesc->mIoHandle);
+ weakSecondaryDescs.push_back(secondaryDesc);
+ }
+ trackSecondaryOutputs.emplace(client->portId(), secondaryOutputIds);
+ client->setSecondaryOutputs(std::move(weakSecondaryDescs));
}
}
}
+ if (!trackSecondaryOutputs.empty()) {
+ mpClientInterface->updateSecondaryOutputs(trackSecondaryOutputs);
+ }
for (audio_stream_type_t stream : streamsToInvalidate) {
- ALOGD("%s Invalidate stream %d due to secondary output change", __func__, stream);
+ ALOGD("%s Invalidate stream %d due to fail getting output for attr", __func__, stream);
mpClientInterface->invalidateStream(stream);
}
}
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 77b5200..cd53073 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -291,4 +291,14 @@
return af->getAudioPort(port);
}
+status_t AudioPolicyService::AudioPolicyClient::updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs) {
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == nullptr) {
+ ALOGW("%s: could not get AudioFlinger", __func__);
+ return PERMISSION_DENIED;
+ }
+ return af->updateSecondaryOutputs(trackSecondaryOutputs);
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 00d9670..6eb33f6 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -735,6 +735,9 @@
status_t getAudioPort(struct audio_port_v7 *port) override;
+ status_t updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index e2d7d17..f7b0565 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -134,6 +134,11 @@
size_t getRoutingUpdatedCounter() const {
return mRoutingUpdatedUpdateCount; }
+ status_t updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
+ return NO_ERROR;
+ }
+
private:
audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index d289e15..1384864 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -91,6 +91,10 @@
status_t getAudioPort(struct audio_port_v7 *port __unused) override {
return INVALID_OPERATION;
};
+ status_t updateSecondaryOutputs(
+ const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
+ return NO_INIT;
+ }
};
} // namespace android
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 329400d..83d2bc9 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -232,6 +232,10 @@
}
}
+ //Derive primary rear/front cameras, and filter their charactierstics.
+ //This needs to be done after all cameras are enumerated and camera ids are sorted.
+ filterSPerfClassCharacteristics();
+
return OK;
}
@@ -302,6 +306,45 @@
filterAPI1SystemCameraLocked(mNormalDeviceIds);
}
+void CameraService::filterSPerfClassCharacteristics() {
+ static int32_t kPerformanceClassLevel =
+ property_get_int32("ro.odm.build.media_performance_class", 0);
+ static bool kIsSPerformanceClass = (kPerformanceClassLevel == 31);
+
+ if (!kIsSPerformanceClass) return;
+
+ // To claim to be S Performance primary cameras, the cameras must be
+ // backward compatible. So performance class primary camera Ids must be API1
+ // compatible.
+ bool firstRearCameraSeen = false, firstFrontCameraSeen = false;
+ for (const auto& cameraId : mNormalDeviceIdsWithoutSystemCamera) {
+ int facing = -1;
+ int orientation = 0;
+ String8 cameraId8(cameraId.c_str());
+ getDeviceVersion(cameraId8, /*out*/&facing, /*out*/&orientation);
+ if (facing == -1) {
+ ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.c_str());
+ return;
+ }
+
+ if ((facing == hardware::CAMERA_FACING_BACK && !firstRearCameraSeen) ||
+ (facing == hardware::CAMERA_FACING_FRONT && !firstFrontCameraSeen)) {
+ mCameraProviderManager->filterSmallJpegSizes(cameraId);
+
+ if (facing == hardware::CAMERA_FACING_BACK) {
+ firstRearCameraSeen = true;
+ }
+ if (facing == hardware::CAMERA_FACING_FRONT) {
+ firstFrontCameraSeen = true;
+ }
+ }
+
+ if (firstRearCameraSeen && firstFrontCameraSeen) {
+ break;
+ }
+ }
+}
+
void CameraService::addStates(const String8 id) {
std::string cameraId(id.c_str());
hardware::camera::common::V1_0::CameraResourceCost cost;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 22dd0db..d1ed59a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -935,6 +935,11 @@
*/
void updateCameraNumAndIds();
+ /**
+ * Filter camera characteristics for S Performance class primary cameras
+ */
+ void filterSPerfClassCharacteristics();
+
// Number of camera devices (excluding hidden secure cameras)
int mNumberOfCameras;
// Number of camera devices (excluding hidden secure cameras and
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 8164df0..bd2e7dc 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -2976,7 +2976,7 @@
const StreamConfiguration &sc = scs[i];
if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
- sc.width <= limit.width && sc.height <= limit.height) {
+ ((sc.width * sc.height) <= (limit.width * limit.height))) {
int64_t minFrameDuration = getMinFrameDurationNs(
{sc.width, sc.height}, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
if (minFrameDuration > MAX_PREVIEW_RECORD_DURATION_NS) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 6dffc5d..46e5d6d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1186,6 +1186,17 @@
return isHiddenPhysicalCameraInternal(cameraId).first;
}
+void CameraProviderManager::filterSmallJpegSizes(const std::string& cameraId) {
+ for (auto& provider : mProviders) {
+ for (auto& deviceInfo : provider->mDevices) {
+ if (deviceInfo->mId == cameraId) {
+ deviceInfo->filterSmallJpegSizes();
+ return;
+ }
+ }
+ }
+}
+
std::pair<bool, CameraProviderManager::ProviderInfo::DeviceInfo *>
CameraProviderManager::isHiddenPhysicalCameraInternal(const std::string& cameraId) const {
auto falseRet = std::make_pair(false, nullptr);
@@ -2562,6 +2573,70 @@
return res;
}
+void CameraProviderManager::ProviderInfo::DeviceInfo3::filterSmallJpegSizes() {
+ static constexpr int FHD_W = 1920;
+ static constexpr int FHD_H = 1080;
+
+ // Remove small JPEG sizes from available stream configurations
+ std::vector<int32_t> newStreamConfigs;
+ camera_metadata_entry streamConfigs =
+ mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ for (size_t i = 0; i < streamConfigs.count; i += 4) {
+ if ((streamConfigs.data.i32[i] == HAL_PIXEL_FORMAT_BLOB) && (streamConfigs.data.i32[i+3] ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) &&
+ (streamConfigs.data.i32[i+1] < FHD_W || streamConfigs.data.i32[i+2] < FHD_H)) {
+ continue;
+ }
+ newStreamConfigs.insert(newStreamConfigs.end(), streamConfigs.data.i32 + i,
+ streamConfigs.data.i32 + i + 4);
+ }
+ if (newStreamConfigs.size() > 0) {
+ mCameraCharacteristics.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ newStreamConfigs.data(), newStreamConfigs.size());
+ }
+
+ // Remove small JPEG sizes from available min frame durations
+ std::vector<int64_t> newMinDurations;
+ camera_metadata_entry minDurations =
+ mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ for (size_t i = 0; i < minDurations.count; i += 4) {
+ if ((minDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) &&
+ (minDurations.data.i64[i+1] < FHD_W || minDurations.data.i64[i+2] < FHD_H)) {
+ continue;
+ }
+ newMinDurations.insert(newMinDurations.end(), minDurations.data.i64 + i,
+ minDurations.data.i64 + i + 4);
+ }
+ if (newMinDurations.size() > 0) {
+ mCameraCharacteristics.update(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+ newMinDurations.data(), newMinDurations.size());
+ }
+
+ // Remove small JPEG sizes from available stall durations
+ std::vector<int64_t> newStallDurations;
+ camera_metadata_entry stallDurations =
+ mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
+ for (size_t i = 0; i < stallDurations.count; i += 4) {
+ if ((stallDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) &&
+ (stallDurations.data.i64[i+1] < FHD_W || stallDurations.data.i64[i+2] < FHD_H)) {
+ continue;
+ }
+ newStallDurations.insert(newStallDurations.end(), stallDurations.data.i64 + i,
+ stallDurations.data.i64 + i + 4);
+ }
+ if (newStallDurations.size() > 0) {
+ mCameraCharacteristics.update(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+ newStallDurations.data(), newStallDurations.size());
+ }
+
+ // Re-generate metadata tags that have dependencies on BLOB sizes
+ auto res = addDynamicDepthTags();
+ if (OK != res) {
+ ALOGE("%s: Failed to append dynamic depth tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+}
+
status_t CameraProviderManager::ProviderInfo::parseProviderName(const std::string& name,
std::string *type, uint32_t *id) {
// Format must be "<type>/<id>"
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 5531dd7..4fde556 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -327,6 +327,8 @@
status_t getSystemCameraKind(const std::string& id, SystemCameraKind *kind) const;
bool isHiddenPhysicalCamera(const std::string& cameraId) const;
+ void filterSmallJpegSizes(const std::string& cameraId);
+
static const float kDepthARTolerance;
private:
// All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
@@ -486,6 +488,7 @@
bool * /*status*/) {
return INVALID_OPERATION;
}
+ virtual void filterSmallJpegSizes() = 0;
template<class InterfaceT>
sp<InterfaceT> startDeviceInterface();
@@ -544,6 +547,7 @@
const hardware::camera::device::V3_7::StreamConfiguration &configuration,
bool *status /*out*/)
override;
+ virtual void filterSmallJpegSizes() override;
DeviceInfo3(const std::string& name, const metadata_vendor_id_t tagId,
const std::string &id, uint16_t minorVersion,
diff --git a/services/mediametrics/statsd_audiopolicy.cpp b/services/mediametrics/statsd_audiopolicy.cpp
index f44b7c4..3d9376e 100644
--- a/services/mediametrics/statsd_audiopolicy.cpp
+++ b/services/mediametrics/statsd_audiopolicy.cpp
@@ -32,7 +32,7 @@
#include <statslog.h>
#include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -50,7 +50,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::AudioPolicyData metrics_proto;
+ ::android::stats::mediametrics_message::AudioPolicyData metrics_proto;
// flesh out the protobuf we'll hand off with our data
//
diff --git a/services/mediametrics/statsd_audiorecord.cpp b/services/mediametrics/statsd_audiorecord.cpp
index 70a67ae..41efcaa 100644
--- a/services/mediametrics/statsd_audiorecord.cpp
+++ b/services/mediametrics/statsd_audiorecord.cpp
@@ -33,7 +33,7 @@
#include "MediaMetricsService.h"
#include "StringUtils.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -50,7 +50,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::AudioRecordData metrics_proto;
+ ::android::stats::mediametrics_message::AudioRecordData metrics_proto;
// flesh out the protobuf we'll hand off with our data
//
diff --git a/services/mediametrics/statsd_audiothread.cpp b/services/mediametrics/statsd_audiothread.cpp
index 34cc923..e9b6dd6 100644
--- a/services/mediametrics/statsd_audiothread.cpp
+++ b/services/mediametrics/statsd_audiothread.cpp
@@ -32,7 +32,7 @@
#include <statslog.h>
#include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -50,7 +50,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::AudioThreadData metrics_proto;
+ ::android::stats::mediametrics_message::AudioThreadData metrics_proto;
#define MM_PREFIX "android.media.audiothread."
diff --git a/services/mediametrics/statsd_audiotrack.cpp b/services/mediametrics/statsd_audiotrack.cpp
index fe269a1..59627ae 100644
--- a/services/mediametrics/statsd_audiotrack.cpp
+++ b/services/mediametrics/statsd_audiotrack.cpp
@@ -33,7 +33,7 @@
#include "MediaMetricsService.h"
#include "StringUtils.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -51,7 +51,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::AudioTrackData metrics_proto;
+ ::android::stats::mediametrics_message::AudioTrackData metrics_proto;
// flesh out the protobuf we'll hand off with our data
//
diff --git a/services/mediametrics/statsd_extractor.cpp b/services/mediametrics/statsd_extractor.cpp
index 2378f33..4ac5621 100644
--- a/services/mediametrics/statsd_extractor.cpp
+++ b/services/mediametrics/statsd_extractor.cpp
@@ -32,7 +32,7 @@
#include <statslog.h>
#include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -50,7 +50,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::ExtractorData metrics_proto;
+ ::android::stats::mediametrics_message::ExtractorData metrics_proto;
std::string format;
if (item->getString("android.media.mediaextractor.fmt", &format)) {
@@ -68,17 +68,17 @@
}
std::string entry_point_string;
- stats::mediametrics::ExtractorData::EntryPoint entry_point =
- stats::mediametrics::ExtractorData_EntryPoint_OTHER;
+ stats::mediametrics_message::ExtractorData::EntryPoint entry_point =
+ stats::mediametrics_message::ExtractorData_EntryPoint_OTHER;
if (item->getString("android.media.mediaextractor.entry", &entry_point_string)) {
if (entry_point_string == "sdk") {
- entry_point = stats::mediametrics::ExtractorData_EntryPoint_SDK;
+ entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_SDK;
} else if (entry_point_string == "ndk-with-jvm") {
- entry_point = stats::mediametrics::ExtractorData_EntryPoint_NDK_WITH_JVM;
+ entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_NDK_WITH_JVM;
} else if (entry_point_string == "ndk-no-jvm") {
- entry_point = stats::mediametrics::ExtractorData_EntryPoint_NDK_NO_JVM;
+ entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_NDK_NO_JVM;
} else {
- entry_point = stats::mediametrics::ExtractorData_EntryPoint_OTHER;
+ entry_point = stats::mediametrics_message::ExtractorData_EntryPoint_OTHER;
}
metrics_proto.set_entry_point(entry_point);
}
diff --git a/services/mediametrics/statsd_nuplayer.cpp b/services/mediametrics/statsd_nuplayer.cpp
index 33da81e..bdee1f2 100644
--- a/services/mediametrics/statsd_nuplayer.cpp
+++ b/services/mediametrics/statsd_nuplayer.cpp
@@ -32,7 +32,7 @@
#include <statslog.h>
#include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -54,7 +54,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::NuPlayerData metrics_proto;
+ ::android::stats::mediametrics_message::NuPlayerData metrics_proto;
// flesh out the protobuf we'll hand off with our data
//
diff --git a/services/mediametrics/statsd_recorder.cpp b/services/mediametrics/statsd_recorder.cpp
index 6edad7c..1b312b5 100644
--- a/services/mediametrics/statsd_recorder.cpp
+++ b/services/mediametrics/statsd_recorder.cpp
@@ -57,8 +57,8 @@
// string kRecorderLogSessionId = "android.media.mediarecorder.log-session-id";
std::string log_session_id;
- if (item->getString("android.media.mediarecorder.log_session_id", &log_session_id)) {
- metrics_proto.set_log_session_id(std::move(log_session_id));
+ if (item->getString("android.media.mediarecorder.log-session-id", &log_session_id)) {
+ metrics_proto.set_log_session_id(log_session_id);
}
// string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
std::string audio_mime;
@@ -214,8 +214,7 @@
<< " video_bitrate:" << video_bitrate
<< " iframe_interval:" << iframe_interval
- // TODO Recorder - add log_session_id
- // << " log_session_id:" << log_session_id
+ << " log_session_id:" << log_session_id
<< " }";
statsdLog->log(android::util::MEDIAMETRICS_RECORDER_REPORTED, log.str());
return true;
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index db61061..f31202b 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -65,6 +65,7 @@
enabled: true,
},
},
+ versions: ["1"],
}
cc_library {
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/.hash b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/.hash
new file mode 100644
index 0000000..df90ffb
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/.hash
@@ -0,0 +1 @@
+7e198281434e9c679b02265e95c51ea25ed180d3
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserver.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserver.aidl
new file mode 100644
index 0000000..73e0e0b
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserver.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+/* @hide */
+interface IResourceObserver {
+ oneway void onStatusChanged(android.media.MediaObservableEvent event, int uid, int pid, in android.media.MediaObservableParcel[] observables);
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserverService.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserverService.aidl
new file mode 100644
index 0000000..c2d60af
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/IResourceObserverService.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+/* @hide */
+interface IResourceObserverService {
+ void registerObserver(android.media.IResourceObserver observer, in android.media.MediaObservableFilter[] filters);
+ void unregisterObserver(android.media.IResourceObserver observer);
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableEvent.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableEvent.aidl
new file mode 100644
index 0000000..a45f0ba
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableEvent.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+/* @hide */
+@Backing(type="long")
+enum MediaObservableEvent {
+ kBusy = 1,
+ kIdle = 2,
+ kAll = -1,
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableFilter.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableFilter.aidl
new file mode 100644
index 0000000..22ae284
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableFilter.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+/* @hide */
+parcelable MediaObservableFilter {
+ android.media.MediaObservableType type;
+ android.media.MediaObservableEvent eventFilter;
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableParcel.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableParcel.aidl
new file mode 100644
index 0000000..2270d87
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableParcel.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+/* @hide */
+parcelable MediaObservableParcel {
+ android.media.MediaObservableType type;
+ long value = 0;
+}
diff --git a/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableType.aidl b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableType.aidl
new file mode 100644
index 0000000..eab3f3f
--- /dev/null
+++ b/services/mediaresourcemanager/aidl_api/resourceobserver_aidl_interface/1/android/media/MediaObservableType.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+/* @hide */
+@Backing(type="int")
+enum MediaObservableType {
+ kInvalid = 0,
+ kVideoSecureCodec = 1000,
+ kVideoNonSecureCodec = 1001,
+}
diff --git a/services/tuner/Android.bp b/services/tuner/Android.bp
index df2b4a3..cd11c88 100644
--- a/services/tuner/Android.bp
+++ b/services/tuner/Android.bp
@@ -32,8 +32,8 @@
":tv_tuner_aidl",
],
imports: [
- "android.hardware.common",
- "android.hardware.common.fmq",
+ "android.hardware.common-V2",
+ "android.hardware.common.fmq-V1",
],
backend: {