Make change and version bump to r_aml_300801500 for mainline module file: apex/manifest_codec.json
Change-Id: I07481206cb5c51c5d1dd6fe0b169b6a20c2b5991
diff --git a/apex/manifest.json b/apex/manifest.json
index a3684cf..81146cb 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media",
- "version": 300801400
+ "version": 300801500
}
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index faf529f..75f9613 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media.swcodec",
- "version": 300801400
+ "version": 300801500
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index c07f3dc..2cd357b 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -618,13 +618,14 @@
}
void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
- if (mInputMetEos ||
- mOutput.lock()->buffers->hasPending() ||
- mPipelineWatcher.lock()->pipelineFull()) {
+ if (mInputMetEos || mPipelineWatcher.lock()->pipelineFull()) {
return;
- } else {
+ }
+ {
Mutexed<Output>::Locked output(mOutput);
- if (!output->buffers || output->buffers->numClientBuffers() >= output->numSlots) {
+ if (!output->buffers ||
+ output->buffers->hasPending() ||
+ output->buffers->numClientBuffers() >= output->numSlots) {
return;
}
}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 7efa67c..df47def 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -742,8 +742,6 @@
void *iMemPointer;
audio_track_cblk_t* cblk;
status_t status;
- std::string flagsAsString;
- std::string originalFlagsAsString;
if (audioFlinger == 0) {
ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId);
@@ -922,15 +920,13 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
- InputFlagConverter::toString(mFlags, flagsAsString);
- InputFlagConverter::toString(mOrigFlags, originalFlagsAsString);
mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(mPortId);
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
.set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
// the following are immutable (at least until restore)
- .set(AMEDIAMETRICS_PROP_FLAGS, flagsAsString.c_str())
- .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, originalFlagsAsString.c_str())
+ .set(AMEDIAMETRICS_PROP_FLAGS, toString(mFlags).c_str())
+ .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
.set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
.set(AMEDIAMETRICS_PROP_TRACKID, mPortId)
.set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str())
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 005d358..32129f0 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1713,16 +1713,12 @@
// is the first log of the AudioTrack and must be present before
// any AudioTrack client logs will be accepted.
- std::string flagsAsString;
- OutputFlagConverter::toString(mFlags, flagsAsString);
- std::string originalFlagsAsString;
- OutputFlagConverter::toString(mOrigFlags, originalFlagsAsString);
mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(mPortId);
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
// the following are immutable
- .set(AMEDIAMETRICS_PROP_FLAGS, flagsAsString.c_str())
- .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, originalFlagsAsString.c_str())
+ .set(AMEDIAMETRICS_PROP_FLAGS, toString(mFlags).c_str())
+ .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
.set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
.set(AMEDIAMETRICS_PROP_TRACKID, mPortId) // dup from key
.set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(mAttributes.content_type).c_str())
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 0906411..84388c9 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -147,6 +147,7 @@
#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
#define AMEDIAMETRICS_PROP_THROTTLEMS "throttleMs" // double
#define AMEDIAMETRICS_PROP_TRACKID "trackId" // int32 port id of track/record
+#define AMEDIAMETRICS_PROP_TRAITS "traits" // string
#define AMEDIAMETRICS_PROP_TYPE "type" // string (thread type)
#define AMEDIAMETRICS_PROP_UNDERRUN "underrun" // int32
#define AMEDIAMETRICS_PROP_UNDERRUNFRAMES "underrunFrames" // int64_t from Thread
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
index 12bd341..af16448 100644
--- a/services/audioflinger/TrackMetrics.h
+++ b/services/audioflinger/TrackMetrics.h
@@ -68,6 +68,7 @@
}
void logConstructor(pid_t creatorPid, uid_t creatorUid,
+ const std::string& traits = {},
audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT) const {
// Once this item is logged by the server, the client can add properties.
// no lock required, all local or const variables.
@@ -76,7 +77,8 @@
.setUid(creatorUid)
.set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)creatorUid)
.set(AMEDIAMETRICS_PROP_EVENT,
- AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR);
+ AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .set(AMEDIAMETRICS_PROP_TRAITS, traits);
// log streamType from the service, since client doesn't know chosen streamType.
if (streamType != AUDIO_STREAM_DEFAULT) {
item.set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(streamType).c_str());
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 9386a42..be2f687 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -602,7 +602,8 @@
}
// Once this item is logged by the server, the client can add properties.
- mTrackMetrics.logConstructor(creatorPid, uid, streamType);
+ const char * const traits = sharedBuffer == 0 ? "" : "static";
+ mTrackMetrics.logConstructor(creatorPid, uid, traits, streamType);
}
AudioFlinger::PlaybackThread::Track::~Track()
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index f819f1b..55de260 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -102,6 +102,7 @@
"libutils",
],
header_libs: [
+ "libaudioutils_headers",
"libmediametrics_headers",
],
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 800f099..78e2c89 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -31,30 +31,131 @@
#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
-// Enable for testing of delivery to statsd
-//#define STATSD
+namespace android::mediametrics {
-// Transmit to statsd in integer or strings
-//#define USE_INT
+// Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
+#define STATSD_ENABLE
-#ifdef USE_INT
-using short_enum_type_t = int32_t;
-using long_enum_type_t = int64_t;
-#define ENUM_EXTRACT(x) (x)
+#ifdef STATSD_ENABLE
+#define CONDITION(INT_VALUE) (INT_VALUE) // allow value
#else
-using short_enum_type_t = std::string;
-using long_enum_type_t = std::string;
-#define ENUM_EXTRACT(x) (x).c_str()
+#define CONDITION(INT_VALUE) (int(0)) // mask value since the proto may not be defined yet.
#endif
-using android::base::DEBUG;
+// Maximum length of a device name.
+static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32;
-namespace android::mediametrics {
+// Transmit Enums to statsd in integer or strings (this must match the atoms.proto)
+static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
+
+// derive types based on integer or strings.
+using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
+using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
+
+// Convert std::string to char *
+template <typename T>
+auto ENUM_EXTRACT(const T& x) {
+ if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
+ return x.c_str();
+ } else {
+ return x;
+ }
+}
+
+static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
+
+/*
+ * For logging purposes, we list all of the MediaMetrics atom fields,
+ * which can then be associated with consecutive arguments to the statsd write.
+ */
+
+static constexpr const char * const AudioRecordDeviceUsageFields[] = {
+ "mediametrics_audiorecorddeviceusage_reported", // proto number
+ "devices",
+ "device_names",
+ "device_time_nanos",
+ "encoding",
+ "frame_count",
+ "interval_count",
+ "sample_rate",
+ "flags",
+ "package_name",
+ "selected_device_id",
+ "caller",
+ "source",
+};
+
+static constexpr const char * const AudioThreadDeviceUsageFields[] = {
+ "mediametrics_audiothreaddeviceusage_reported",
+ "devices",
+ "device_names",
+ "device_time_nanos",
+ "encoding",
+ "frame_count",
+ "interval_count",
+ "sample_rate",
+ "flags",
+ "xruns",
+ "type",
+};
+
+static constexpr const char * const AudioTrackDeviceUsageFields[] = {
+ "mediametrics_audiotrackdeviceusage_reported",
+ "devices",
+ "device_names",
+ "device_time_nanos",
+ "encoding",
+ "frame_count",
+ "interval_count",
+ "sample_rate",
+ "flags",
+ "xruns",
+ "package_name",
+ "device_latency_millis",
+ "device_startup_millis",
+ "device_volume",
+ "selected_device_id",
+ "stream_type",
+ "usage",
+ "content_type",
+ "caller",
+ "traits",
+};
+
+static constexpr const char * const AudioDeviceConnectionFields[] = {
+ "mediametrics_audiodeviceconnection_reported",
+ "input_devices",
+ "output_devices",
+ "device_names",
+ "result",
+ "time_to_connect_millis",
+ "connection_count",
+};
+
+/**
+ * sendToStatsd is a helper method that sends the arguments to statsd
+ * and returns a pair { result, summary_string }.
+ */
+template <size_t N, typename ...Types>
+std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
+{
+ int result = 0;
+ std::stringstream ss;
+
+#ifdef STATSD_ENABLE
+ result = android::util::stats_write(args...);
+ ss << "result:" << result;
+#endif
+ ss << " { ";
+ stringutils::fieldPrint(ss, fields, args...);
+ ss << "}";
+ return { result, ss.str() };
+}
AudioAnalytics::AudioAnalytics()
: mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
{
- SetMinimumLogSeverity(DEBUG); // for LOG().
+ SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
ALOGD("%s", __func__);
// Add action to save AnalyticsState if audioserver is restarted.
@@ -220,11 +321,26 @@
ll -= l;
}
+ if (ll > 0) {
+ // Print the statsd atoms we sent out.
+ const std::string statsd = mStatsdLog.dumpToString(" " /* prefix */, ll - 1);
+ const size_t n = std::count(statsd.begin(), statsd.end(), '\n') + 1; // we control this.
+ if ((size_t)ll >= n) {
+ if (n == 1) {
+ ss << "Statsd atoms: empty or truncated\n";
+ } else {
+ ss << "Statsd atoms:\n" << statsd;
+ }
+ ll -= n;
+ }
+ }
+
if (ll > 0 && prefix == nullptr) {
auto [s, l] = mAudioPowerUsage.dump(ll);
ss << s;
ll -= l;
}
+
return { ss.str(), lines - ll };
}
@@ -312,20 +428,25 @@
// Get connected device name if from bluetooth.
bool isBluetooth = false;
- std::string deviceNames; // we only have one device name at this time.
+
+ std::string inputDeviceNames; // not filled currently.
+ std::string outputDeviceNames;
if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
isBluetooth = true;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
- "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
+ "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
// Remove | if present
- stringutils::replace(deviceNames, "|", '?');
+ stringutils::replace(outputDeviceNames, "|", '?');
+ if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
+ outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
+ }
}
switch (itemType) {
case RECORD: {
std::string callerName;
- mAudioAnalytics.mAnalyticsState->timeMachine().get(
- key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
+ const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
std::string packageName;
int64_t versionCode = 0;
@@ -350,10 +471,10 @@
const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
- LOG(DEBUG) << "key:" << key
+ LOG(LOG_LEVEL) << "key:" << key
<< " id:" << id
<< " inputDevices:" << inputDevices << "(" << inputDeviceBits
- << ") deviceNames:" << deviceNames
+ << ") inputDeviceNames:" << inputDeviceNames
<< " deviceTimeNs:" << deviceTimeNs
<< " encoding:" << encoding << "(" << encodingForStats
<< ") frameCount:" << frameCount
@@ -364,12 +485,12 @@
<< " selectedDeviceId:" << selectedDeviceId
<< " callerName:" << callerName << "(" << callerNameForStats
<< ") source:" << source << "(" << sourceForStats << ")";
-#ifdef STATSD
- if (mAudioAnalytics.mDeliverStatistics) {
- (void)android::util::stats_write(
- android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED
+ if (clientCalled // only log if client app called AudioRecord.
+ && mAudioAnalytics.mDeliverStatistics) {
+ const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
, ENUM_EXTRACT(inputDeviceBits)
- , deviceNames.c_str()
+ , inputDeviceNames.c_str()
, deviceTimeNs
, ENUM_EXTRACT(encodingForStats)
, frameCount
@@ -382,8 +503,9 @@
, ENUM_EXTRACT(callerNameForStats)
, ENUM_EXTRACT(sourceForStats)
);
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
}
-#endif
} break;
case THREAD: {
std::string type;
@@ -400,11 +522,12 @@
: types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
- LOG(DEBUG) << "key:" << key
+ LOG(LOG_LEVEL) << "key:" << key
<< " id:" << id
<< " inputDevices:" << inputDevices << "(" << inputDeviceBits
<< ") outputDevices:" << outputDevices << "(" << outputDeviceBits
- << ") deviceNames:" << deviceNames
+ << ") inputDeviceNames:" << inputDeviceNames
+ << " outputDeviceNames:" << outputDeviceNames
<< " deviceTimeNs:" << deviceTimeNs
<< " encoding:" << encoding << "(" << encodingForStats
<< ") frameCount:" << frameCount
@@ -414,13 +537,11 @@
<< " flags:" << flags << "(" << flagsForStats
<< ") type:" << type << "(" << typeForStats
<< ")";
-#ifdef STATSD
if (mAudioAnalytics.mDeliverStatistics) {
- (void)android::util::stats_write(
- android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED
- , ENUM_EXTRACT(inputDeviceBits)
- , ENUM_EXTRACT(outputDeviceBits)
- , deviceNames.c_str()
+ const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
+ , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
+ , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
, deviceTimeNs
, ENUM_EXTRACT(encodingForStats)
, frameCount
@@ -430,13 +551,15 @@
, underrun
, ENUM_EXTRACT(typeForStats)
);
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
}
-#endif
} break;
case TRACK: {
std::string callerName;
- mAudioAnalytics.mAnalyticsState->timeMachine().get(
- key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
+ const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
+
std::string contentType;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
@@ -470,6 +593,9 @@
std::string streamType;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
+ std::string traits;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_TRAITS, &traits);
int32_t underrun = 0;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
@@ -485,12 +611,14 @@
const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
const auto streamTypeForStats =
types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
+ const auto traitsForStats =
+ types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
- LOG(DEBUG) << "key:" << key
+ LOG(LOG_LEVEL) << "key:" << key
<< " id:" << id
<< " outputDevices:" << outputDevices << "(" << outputDeviceBits
- << ") deviceNames:" << deviceNames
+ << ") outputDeviceNames:" << outputDeviceNames
<< " deviceTimeNs:" << deviceTimeNs
<< " encoding:" << encoding << "(" << encodingForStats
<< ") frameCount:" << frameCount
@@ -508,14 +636,15 @@
<< " playbackSpeed:" << playbackSpeed
<< " selectedDeviceId:" << selectedDeviceId
<< " streamType:" << streamType << "(" << streamTypeForStats
+ << ") traits:" << traits << "(" << traitsForStats
<< ") usage:" << usage << "(" << usageForStats
<< ")";
-#ifdef STATSD
- if (mAudioAnalytics.mDeliverStatistics) {
- (void)android::util::stats_write(
- android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED
+ if (clientCalled // only log if client app called AudioTracks
+ && mAudioAnalytics.mDeliverStatistics) {
+ const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
, ENUM_EXTRACT(outputDeviceBits)
- , deviceNames.c_str()
+ , outputDeviceNames.c_str()
, deviceTimeNs
, ENUM_EXTRACT(encodingForStats)
, frameCount
@@ -523,7 +652,6 @@
, sampleRate
, ENUM_EXTRACT(flagsForStats)
, underrun
-
, packageName.c_str()
, (float)deviceLatencyMs
, (float)deviceStartupMs
@@ -533,9 +661,11 @@
, ENUM_EXTRACT(usageForStats)
, ENUM_EXTRACT(contentTypeForStats)
, ENUM_EXTRACT(callerNameForStats)
+ , ENUM_EXTRACT(traitsForStats)
);
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
}
-#endif
} break;
}
@@ -592,23 +722,26 @@
const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
"AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
- LOG(DEBUG) << "key:" << key
+ LOG(LOG_LEVEL) << "key:" << key
<< " A2DP SUCCESS"
<< " outputDevices:" << outputDeviceBits
+ << " deviceName:" << mA2dpDeviceName
<< " connectionTimeMs:" << connectionTimeMs;
-#ifdef STATSD
if (mAudioAnalytics.mDeliverStatistics) {
const long_enum_type_t inputDeviceBits{};
- (void)android::util::stats_write(
- android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
+
+ const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
, ENUM_EXTRACT(inputDeviceBits)
, ENUM_EXTRACT(outputDeviceBits)
+ , mA2dpDeviceName.c_str()
, types::DEVICE_CONNECTION_RESULT_SUCCESS
, connectionTimeMs
, /* connection_count */ 1
);
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
}
-#endif
}
}
@@ -620,13 +753,17 @@
std::string state;
item->get(AMEDIAMETRICS_PROP_STATE, &state);
if (state != "connected") return;
+
+ std::string name;
+ item->get(AMEDIAMETRICS_PROP_NAME, &name);
{
std::lock_guard l(mLock);
mA2dpConnectionRequestNs = atNs;
++mA2dpConnectionRequests;
+ mA2dpDeviceName = name;
}
- ALOGD("(key=%s) a2dp connection request atNs:%lld",
- key.c_str(), (long long)atNs);
+ ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
+ key.c_str(), name.c_str(), (long long)atNs);
// TODO: attempt to cancel a timed event, rather than let it expire.
mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
}
@@ -635,29 +772,29 @@
std::lock_guard l(mLock);
if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
-#ifdef STATSD
const long_enum_type_t inputDeviceBits{};
-#endif
const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
"AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
if (mA2dpConnectionServiceNs == 0) {
++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
- LOG(DEBUG) << "A2DP CANCEL"
- << " outputDevices:" << outputDeviceBits;
-#ifdef STATSD
+ LOG(LOG_LEVEL) << "A2DP CANCEL"
+ << " outputDevices:" << outputDeviceBits
+ << " deviceName:" << mA2dpDeviceName;
if (mAudioAnalytics.mDeliverStatistics) {
- (void)android::util::stats_write(
- android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
+ const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
, ENUM_EXTRACT(inputDeviceBits)
, ENUM_EXTRACT(outputDeviceBits)
+ , mA2dpDeviceName.c_str()
, types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
, /* connection_time_ms */ 0.f
, /* connection_count */ 1
);
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
}
-#endif
return;
}
@@ -668,20 +805,22 @@
mA2dpConnectionServiceNs = 0;
++mA2dpConnectionUnknowns; // connection result unknown
- LOG(DEBUG) << "A2DP UNKNOWN"
- << " outputDevices:" << outputDeviceBits;
-#ifdef STATSD
+ LOG(LOG_LEVEL) << "A2DP UNKNOWN"
+ << " outputDevices:" << outputDeviceBits
+ << " deviceName:" << mA2dpDeviceName;
if (mAudioAnalytics.mDeliverStatistics) {
- (void)android::util::stats_write(
- android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
+ const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
, ENUM_EXTRACT(inputDeviceBits)
, ENUM_EXTRACT(outputDeviceBits)
+ , mA2dpDeviceName.c_str()
, types::DEVICE_CONNECTION_RESULT_UNKNOWN
, /* connection_time_ms */ 0.f
, /* connection_count */ 1
);
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
}
-#endif
}
} // namespace android::mediametrics
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/AudioAnalytics.h
index 138ddcc..809de19 100644
--- a/services/mediametrics/AudioAnalytics.h
+++ b/services/mediametrics/AudioAnalytics.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/thread_annotations.h>
+#include <audio_utils/SimpleLog.h>
#include "AnalyticsActions.h"
#include "AnalyticsState.h"
#include "AudioPowerUsage.h"
@@ -122,6 +123,8 @@
TimedAction mTimedAction; // locked internally
+ SimpleLog mStatsdLog{16 /* log lines */}; // locked internally
+
// DeviceUse is a nested class which handles audio device usage accounting.
// We define this class at the end to ensure prior variables all properly constructed.
// TODO: Track / Thread interaction
@@ -173,6 +176,7 @@
AudioAnalytics &mAudioAnalytics;
mutable std::mutex mLock;
+ std::string mA2dpDeviceName;
int64_t mA2dpConnectionRequestNs GUARDED_BY(mLock) = 0; // Time for BT service request.
int64_t mA2dpConnectionServiceNs GUARDED_BY(mLock) = 0; // Time audio service agrees.
diff --git a/services/mediametrics/AudioTypes.cpp b/services/mediametrics/AudioTypes.cpp
index 2a2dbaf..aa44447 100644
--- a/services/mediametrics/AudioTypes.cpp
+++ b/services/mediametrics/AudioTypes.cpp
@@ -20,7 +20,30 @@
namespace android::mediametrics::types {
-std::unordered_map<std::string, int64_t>& getAudioDeviceInMap() {
+const std::unordered_map<std::string, int32_t>& getAudioCallerNameMap() {
+ // DO NOT MODIFY VALUES (OK to add new ones).
+ // This may be found in frameworks/av/media/libmediametrics/include/MediaMetricsConstants.h
+ static std::unordered_map<std::string, int32_t> map{
+ {"unknown", 0}, // callerName not set
+ {"aaudio", 1}, // Native AAudio
+ {"java", 2}, // Java API layer
+ {"media", 3}, // libmedia (mediaplayer)
+ {"opensles", 4}, // Open SLES
+ {"rtp", 5}, // RTP communication
+ {"soundpool", 6}, // SoundPool
+ {"tonegenerator", 7}, // dial tones
+ // R values above.
+ };
+ return map;
+}
+
+// A map in case we need to return a flag for input devices.
+// This is 64 bits (and hence not the same as audio_device_t) because we need extra
+// bits to represent new devices.
+// NOT USED FOR R. We do not use int64 flags.
+// This can be out of date for now, as it is unused even for string validation
+// (instead TypeConverter<InputDeviceTraits> is used).
+const std::unordered_map<std::string, int64_t>& getAudioDeviceInMap() {
// DO NOT MODIFY VALUES (OK to add new ones). This does NOT match audio_device_t.
static std::unordered_map<std::string, int64_t> map{
{"AUDIO_DEVICE_IN_COMMUNICATION", 1LL << 0},
@@ -57,7 +80,13 @@
return map;
}
-std::unordered_map<std::string, int64_t>& getAudioDeviceOutMap() {
+// A map in case we need to return a flag for output devices.
+// This is 64 bits (and hence not the same as audio_device_t) because we need extra
+// bits to represent new devices.
+// NOT USED FOR R. We do not use int64 flags.
+// This can be out of date for now, as it is unused even for string validation
+// (instead TypeConverter<OutputDeviceTraits> is used).
+const std::unordered_map<std::string, int64_t>& getAudioDeviceOutMap() {
// DO NOT MODIFY VALUES (OK to add new ones). This does NOT match audio_device_t.
static std::unordered_map<std::string, int64_t> map{
{"AUDIO_DEVICE_OUT_EARPIECE", 1LL << 0},
@@ -96,24 +125,7 @@
return map;
}
-std::unordered_map<std::string, int32_t>& getCallerNameMap() {
- // DO NOT MODIFY VALUES (OK to add new ones).
- // This may be found in frameworks/av/media/libmediametrics/include/MediaMetricsConstants.h
- static std::unordered_map<std::string, int32_t> map{
- {"aaudio", 0}, // Native AAudio
- {"java", 1}, // Java API layer
- {"media", 2}, // libmedia (mediaplayer)
- {"opensles", 3}, // Open SLES
- {"rtp", 4}, // RTP communication
- {"soundpool", 5}, // SoundPool
- {"tonegenerator", 6}, // dial tones
- {"unknown", 7}, // callerName not set
- // R values above.
- };
- return map;
-}
-
-std::unordered_map<std::string, int32_t>& getThreadTypeMap() {
+const std::unordered_map<std::string, int32_t>& getAudioThreadTypeMap() {
// DO NOT MODIFY VALUES (OK to add new ones).
// This may be found in frameworks/av/services/audioflinger/Threads.h
static std::unordered_map<std::string, int32_t> map{
@@ -130,6 +142,15 @@
return map;
}
+const std::unordered_map<std::string, int32_t>& getAudioTrackTraitsMap() {
+ // DO NOT MODIFY VALUES (OK to add new ones).
+ static std::unordered_map<std::string, int32_t> map{
+ {"static", (1 << 0)}, // A static track
+ // R values above.
+ };
+ return map;
+}
+
// Helper: Create the corresponding int32 from string flags split with '|'.
template <typename Traits>
int32_t int32FromFlags(const std::string &flags)
@@ -163,6 +184,37 @@
return sFlags;
}
+template <typename M>
+std::string validateStringFromMap(const std::string &str, const M& map)
+{
+ if (str.empty()) return {};
+
+ const auto result = stringutils::split(str, "|");
+ std::stringstream ss;
+ for (const auto &s : result) {
+ if (map.count(s) > 0) {
+ if (ss.tellp() > 0) ss << "|";
+ ss << s;
+ }
+ }
+ return ss.str();
+}
+
+template <typename M>
+typename M::mapped_type flagsFromMap(const std::string &str, const M& map)
+{
+ if (str.empty()) return {};
+
+ const auto result = stringutils::split(str, "|");
+ typename M::mapped_type value{};
+ for (const auto &s : result) {
+ auto it = map.find(s);
+ if (it == map.end()) continue;
+ value |= it->second;
+ }
+ return value;
+}
+
template <>
int32_t lookup<CONTENT_TYPE>(const std::string &contentType)
{
@@ -178,7 +230,7 @@
{
AudioContentTraits::Type value;
if (!TypeConverter<AudioContentTraits>::fromString(contentType, value)) {
- return "UNKNOWN";
+ return "";
}
return contentType.c_str() + sizeof("AUDIO_CONTENT_TYPE");
}
@@ -198,7 +250,7 @@
{
FormatTraits::Type value;
if (!TypeConverter<FormatTraits>::fromString(encoding, value)) {
- return "INVALID";
+ return "";
}
return encoding.c_str() + sizeof("AUDIO_FORMAT");
}
@@ -242,7 +294,7 @@
{
SourceTraits::Type value;
if (!TypeConverter<SourceTraits>::fromString(sourceType, value)) {
- return "DEFAULT";
+ return "";
}
return sourceType.c_str() + sizeof("AUDIO_SOURCE");
}
@@ -262,7 +314,7 @@
{
StreamTraits::Type value;
if (!TypeConverter<StreamTraits>::fromString(streamType, value)) {
- return "DEFAULT";
+ return "";
}
return streamType.c_str() + sizeof("AUDIO_STREAM");
}
@@ -282,7 +334,7 @@
{
UsageTraits::Type value;
if (!TypeConverter<UsageTraits>::fromString(usage, value)) {
- return "UNKNOWN";
+ return "";
}
return usage.c_str() + sizeof("AUDIO_USAGE");
}
@@ -290,54 +342,40 @@
template <>
int64_t lookup<INPUT_DEVICE>(const std::string &inputDevice)
{
- auto& map = getAudioDeviceInMap();
- auto it = map.find(inputDevice);
- if (it == map.end()) {
- return 0;
- }
- return it->second;
+ // NOT USED FOR R.
+ // Returns a set of bits, each one representing a device in inputDevice.
+ // This is a 64 bit integer, not the same as audio_device_t.
+ return flagsFromMap(inputDevice, getAudioDeviceInMap());
}
template <>
std::string lookup<INPUT_DEVICE>(const std::string &inputDevice)
{
- auto& map = getAudioDeviceInMap();
- auto it = map.find(inputDevice);
- if (it == map.end()) {
- return "NONE";
- }
- return inputDevice.c_str() + sizeof("AUDIO_DEVICE_IN");
+ return stringFromFlags<InputDeviceTraits>(inputDevice, sizeof("AUDIO_DEVICE_IN"));
}
template <>
int64_t lookup<OUTPUT_DEVICE>(const std::string &outputDevice)
{
- auto& map = getAudioDeviceOutMap();
- auto it = map.find(outputDevice);
- if (it == map.end()) {
- return 0; // nothing
- }
- return it->second;
+ // NOT USED FOR R.
+ // Returns a set of bits, each one representing a device in outputDevice.
+ // This is a 64 bit integer, not the same as audio_device_t.
+ return flagsFromMap(outputDevice, getAudioDeviceOutMap());
}
template <>
std::string lookup<OUTPUT_DEVICE>(const std::string &outputDevice)
{
- auto& map = getAudioDeviceOutMap();
- auto it = map.find(outputDevice);
- if (it == map.end()) {
- return "NONE";
- }
- return outputDevice.c_str() + sizeof("AUDIO_DEVICE_OUT");
+ return stringFromFlags<OutputDeviceTraits>(outputDevice, sizeof("AUDIO_DEVICE_OUT"));
}
template <>
int32_t lookup<CALLER_NAME>(const std::string &callerName)
{
- auto& map = getCallerNameMap();
+ auto& map = getAudioCallerNameMap();
auto it = map.find(callerName);
if (it == map.end()) {
- return 7; // return unknown
+ return 0; // return unknown
}
return it->second;
}
@@ -345,10 +383,10 @@
template <>
std::string lookup<CALLER_NAME>(const std::string &callerName)
{
- auto& map = getCallerNameMap();
+ auto& map = getAudioCallerNameMap();
auto it = map.find(callerName);
if (it == map.end()) {
- return "unknown";
+ return "";
}
return callerName;
}
@@ -356,7 +394,7 @@
template <>
int32_t lookup<THREAD_TYPE>(const std::string &threadType)
{
- auto& map = getThreadTypeMap();
+ auto& map = getAudioThreadTypeMap();
auto it = map.find(threadType);
if (it == map.end()) {
return -1; // note this as an illegal thread value as we don't have unknown here.
@@ -367,10 +405,10 @@
template <>
std::string lookup<THREAD_TYPE>(const std::string &threadType)
{
- auto& map = getThreadTypeMap();
+ auto& map = getAudioThreadTypeMap();
auto it = map.find(threadType);
if (it == map.end()) {
- return "UNKNOWN";
+ return "";
}
return threadType;
}
@@ -380,4 +418,16 @@
return threadType == "RECORD" || threadType == "MMAP_CAPTURE";
}
+template <>
+std::string lookup<TRACK_TRAITS>(const std::string &traits)
+{
+ return validateStringFromMap(traits, getAudioTrackTraitsMap());
+}
+
+template <>
+int32_t lookup<TRACK_TRAITS>(const std::string &traits)
+{
+ return flagsFromMap(traits, getAudioTrackTraitsMap());
+}
+
} // namespace android::mediametrics::types
diff --git a/services/mediametrics/AudioTypes.h b/services/mediametrics/AudioTypes.h
index a094e6e..e1deeb1 100644
--- a/services/mediametrics/AudioTypes.h
+++ b/services/mediametrics/AudioTypes.h
@@ -21,17 +21,19 @@
namespace android::mediametrics::types {
-// Helper methods that map mediametrics logged strings to
-// integer codes.
-std::unordered_map<std::string, int64_t>& getAudioDeviceInMap();
-std::unordered_map<std::string, int64_t>& getAudioDeviceOutMap();
-std::unordered_map<std::string, int32_t>& getCallerNameMap();
-std::unordered_map<std::string, int32_t>& getThreadTypeMap();
+// Helper methods that map mediametrics logged strings to integer codes.
+// In R we do not use the integer codes, but rather we can use these maps
+// to validate correct strings.
+const std::unordered_map<std::string, int32_t>& getAudioCallerNameMap();
+const std::unordered_map<std::string, int64_t>& getAudioDeviceInMap();
+const std::unordered_map<std::string, int64_t>& getAudioDeviceOutMap();
+const std::unordered_map<std::string, int32_t>& getAudioThreadTypeMap();
+const std::unordered_map<std::string, int32_t>& getAudioTrackTraitsMap();
// Enumeration for the device connection results.
enum DeviceConnectionResult : int32_t {
- DEVICE_CONNECTION_RESULT_UNKNOWN = 0, // Success is unknown.
- DEVICE_CONNECTION_RESULT_SUCCESS = 1, // Audio delivered
+ DEVICE_CONNECTION_RESULT_SUCCESS = 0, // Audio delivered
+ DEVICE_CONNECTION_RESULT_UNKNOWN = 1, // Success is unknown.
DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL = 2, // Canceled in Java service
// Do not modify the constants above after R. Adding new constants is fine.
};
@@ -48,6 +50,7 @@
SOURCE_TYPE,
STREAM_TYPE,
THREAD_TYPE,
+ TRACK_TRAITS,
USAGE,
};
diff --git a/services/mediametrics/StringUtils.h b/services/mediametrics/StringUtils.h
index d878720..7a8bbee 100644
--- a/services/mediametrics/StringUtils.h
+++ b/services/mediametrics/StringUtils.h
@@ -22,6 +22,30 @@
namespace android::mediametrics::stringutils {
/**
+ * fieldPrint is a helper method that logs to a stringstream a sequence of
+ * field names (in a fixed size array) together with a variable number of arg parameters.
+ *
+ * stringstream << field[0] << ":" << arg0 << " ";
+ * stringstream << field[1] << ":" << arg1 << " ";
+ * ...
+ * stringstream << field[N-1] << ":" << arg{N-1} << " ";
+ *
+ * The number of fields must exactly match the (variable) arguments.
+ *
+ * Example:
+ *
+ * const char * const fields[] = { "integer" };
+ * std::stringstream ss;
+ * fieldPrint(ss, fields, int(10));
+ */
+template <size_t N, typename... Targs>
+void fieldPrint(std::stringstream& ss, const char * const (& fields)[N], Targs... args) {
+ static_assert(N == sizeof...(args)); // guarantee #fields == #args
+ auto fptr = fields; // get a pointer to the base of fields array
+ ((ss << *fptr++ << ":" << args << " "), ...); // (fold expression), send to stringstream.
+}
+
+/**
* Return string tokens from iterator, separated by spaces and reserved chars.
*/
std::string tokenizer(std::string::const_iterator& it,
diff --git a/services/mediametrics/tests/Android.bp b/services/mediametrics/tests/Android.bp
index bdeda30..c2e0759 100644
--- a/services/mediametrics/tests/Android.bp
+++ b/services/mediametrics/tests/Android.bp
@@ -21,6 +21,10 @@
"libutils",
],
+ header_libs: [
+ "libaudioutils_headers",
+ ],
+
srcs: [
"mediametrics_tests.cpp",
],
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 7da6306..478355b 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -18,12 +18,16 @@
#include <utils/Log.h>
#include "MediaMetricsService.h"
-#include "StringUtils.h"
#include <stdio.h>
+#include <unordered_set>
#include <gtest/gtest.h>
#include <media/MediaMetricsItem.h>
+#include <system/audio.h>
+
+#include "AudioTypes.h"
+#include "StringUtils.h"
using namespace android;
@@ -36,6 +40,15 @@
return count;
}
+template <typename M>
+ssize_t countDuplicates(const M& map) {
+ std::unordered_set<typename M::mapped_type> s;
+ for (const auto &m : map) {
+ s.emplace(m.second);
+ }
+ return map.size() - s.size();
+}
+
TEST(mediametrics_tests, startsWith) {
std::string s("test");
ASSERT_EQ(true, android::mediametrics::startsWith(s, "te"));
@@ -804,7 +817,7 @@
// TODO: Verify contents of AudioAnalytics.
// Currently there is no getter API in AudioAnalytics besides dump.
- ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
+ ASSERT_EQ(11, audioAnalytics.dump(1000).second /* lines */);
ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
// untrusted entities can add to an existing key
@@ -840,7 +853,7 @@
// TODO: Verify contents of AudioAnalytics.
// Currently there is no getter API in AudioAnalytics besides dump.
- ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
+ ASSERT_EQ(11, audioAnalytics.dump(1000).second /* lines */);
ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
// untrusted entities can add to an existing key
@@ -926,6 +939,132 @@
ASSERT_EQ((size_t)1, timedAction.size());
}
+// Ensure we don't introduce unexpected duplicates into our maps.
+TEST(mediametrics_tests, audio_types_tables) {
+ using namespace android::mediametrics::types;
+
+ ASSERT_EQ(0, countDuplicates(getAudioCallerNameMap()));
+ ASSERT_EQ(2, countDuplicates(getAudioDeviceInMap())); // has dups
+ ASSERT_EQ(1, countDuplicates(getAudioDeviceOutMap())); // has dups
+ ASSERT_EQ(0, countDuplicates(getAudioThreadTypeMap()));
+ ASSERT_EQ(0, countDuplicates(getAudioTrackTraitsMap()));
+}
+
+// Check our string validation (before logging to statsd).
+// This variant checks the logged, possibly shortened string.
+TEST(mediametrics_tests, audio_types_string) {
+ using namespace android::mediametrics::types;
+
+ ASSERT_EQ("java", (lookup<CALLER_NAME, std::string>)("java"));
+ ASSERT_EQ("", (lookup<CALLER_NAME, std::string>)("random"));
+
+ ASSERT_EQ("SPEECH", (lookup<CONTENT_TYPE, std::string>)("AUDIO_CONTENT_TYPE_SPEECH"));
+ ASSERT_EQ("", (lookup<CONTENT_TYPE, std::string>)("random"));
+
+ ASSERT_EQ("FLAC", (lookup<ENCODING, std::string>)("AUDIO_FORMAT_FLAC"));
+ ASSERT_EQ("", (lookup<ENCODING, std::string>)("random"));
+
+ ASSERT_EQ("USB_DEVICE", (lookup<INPUT_DEVICE, std::string>)("AUDIO_DEVICE_IN_USB_DEVICE"));
+ ASSERT_EQ("BUILTIN_MIC|WIRED_HEADSET", (lookup<INPUT_DEVICE, std::string>)(
+ "AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET"));
+ ASSERT_EQ("", (lookup<INPUT_DEVICE, std::string>)("random"));
+
+ ASSERT_EQ("RAW", (lookup<INPUT_FLAG, std::string>)("AUDIO_INPUT_FLAG_RAW"));
+ ASSERT_EQ("HW_AV_SYNC|VOIP_TX", (lookup<INPUT_FLAG, std::string>)(
+ "AUDIO_INPUT_FLAG_HW_AV_SYNC|AUDIO_INPUT_FLAG_VOIP_TX"));
+ ASSERT_EQ("", (lookup<INPUT_FLAG, std::string>)("random"));
+
+ ASSERT_EQ("BLUETOOTH_SCO_CARKIT",
+ (lookup<OUTPUT_DEVICE, std::string>)("AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"));
+ ASSERT_EQ("SPEAKER|HDMI", (lookup<OUTPUT_DEVICE, std::string>)(
+ "AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI"));
+ ASSERT_EQ("", (lookup<OUTPUT_DEVICE, std::string>)("random"));
+
+ ASSERT_EQ("PRIMARY", (lookup<OUTPUT_FLAG, std::string>)("AUDIO_OUTPUT_FLAG_PRIMARY"));
+ ASSERT_EQ("DEEP_BUFFER|NON_BLOCKING", (lookup<OUTPUT_FLAG, std::string>)(
+ "AUDIO_OUTPUT_FLAG_DEEP_BUFFER|AUDIO_OUTPUT_FLAG_NON_BLOCKING"));
+ ASSERT_EQ("", (lookup<OUTPUT_FLAG, std::string>)("random"));
+
+ ASSERT_EQ("MIC", (lookup<SOURCE_TYPE, std::string>)("AUDIO_SOURCE_MIC"));
+ ASSERT_EQ("", (lookup<SOURCE_TYPE, std::string>)("random"));
+
+ ASSERT_EQ("TTS", (lookup<STREAM_TYPE, std::string>)("AUDIO_STREAM_TTS"));
+ ASSERT_EQ("", (lookup<STREAM_TYPE, std::string>)("random"));
+
+ ASSERT_EQ("DIRECT", (lookup<THREAD_TYPE, std::string>)("DIRECT"));
+ ASSERT_EQ("", (lookup<THREAD_TYPE, std::string>)("random"));
+
+ ASSERT_EQ("static", (lookup<TRACK_TRAITS, std::string>)("static"));
+ ASSERT_EQ("", (lookup<TRACK_TRAITS, std::string>)("random"));
+
+ ASSERT_EQ("VOICE_COMMUNICATION",
+ (lookup<USAGE, std::string>)("AUDIO_USAGE_VOICE_COMMUNICATION"));
+ ASSERT_EQ("", (lookup<USAGE, std::string>)("random"));
+}
+
+// Check our string validation (before logging to statsd).
+// This variant checks integral value logging.
+TEST(mediametrics_tests, audio_types_integer) {
+ using namespace android::mediametrics::types;
+
+ ASSERT_EQ(2, (lookup<CALLER_NAME, int32_t>)("java"));
+ ASSERT_EQ(0, (lookup<CALLER_NAME, int32_t>)("random")); // 0 == unknown
+
+ ASSERT_EQ((int32_t)AUDIO_CONTENT_TYPE_SPEECH,
+ (lookup<CONTENT_TYPE, int32_t>)("AUDIO_CONTENT_TYPE_SPEECH"));
+ ASSERT_EQ((int32_t)AUDIO_CONTENT_TYPE_UNKNOWN, (lookup<CONTENT_TYPE, int32_t>)("random"));
+
+ ASSERT_EQ((int32_t)AUDIO_FORMAT_FLAC, (lookup<ENCODING, int32_t>)("AUDIO_FORMAT_FLAC"));
+ ASSERT_EQ((int32_t)AUDIO_FORMAT_INVALID, (lookup<ENCODING, int32_t>)("random"));
+
+ ASSERT_EQ(getAudioDeviceInMap().at("AUDIO_DEVICE_IN_USB_DEVICE"),
+ (lookup<INPUT_DEVICE, int64_t>)("AUDIO_DEVICE_IN_USB_DEVICE"));
+ ASSERT_EQ(getAudioDeviceInMap().at("AUDIO_DEVICE_IN_BUILTIN_MIC")
+ | getAudioDeviceInMap().at("AUDIO_DEVICE_IN_WIRED_HEADSET"),
+ (lookup<INPUT_DEVICE, int64_t>)(
+ "AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET"));
+ ASSERT_EQ(0, (lookup<INPUT_DEVICE, int64_t>)("random"));
+
+ ASSERT_EQ((int32_t)AUDIO_INPUT_FLAG_RAW,
+ (lookup<INPUT_FLAG, int32_t>)("AUDIO_INPUT_FLAG_RAW"));
+ ASSERT_EQ((int32_t)AUDIO_INPUT_FLAG_HW_AV_SYNC
+ | (int32_t)AUDIO_INPUT_FLAG_VOIP_TX,
+ (lookup<INPUT_FLAG, int32_t>)(
+ "AUDIO_INPUT_FLAG_HW_AV_SYNC|AUDIO_INPUT_FLAG_VOIP_TX"));
+ ASSERT_EQ(0, (lookup<INPUT_FLAG, int32_t>)("random"));
+
+ ASSERT_EQ(getAudioDeviceOutMap().at("AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"),
+ (lookup<OUTPUT_DEVICE, int64_t>)("AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"));
+ ASSERT_EQ(getAudioDeviceOutMap().at("AUDIO_DEVICE_OUT_SPEAKER")
+ | getAudioDeviceOutMap().at("AUDIO_DEVICE_OUT_HDMI"),
+ (lookup<OUTPUT_DEVICE, int64_t>)(
+ "AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI"));
+ ASSERT_EQ(0, (lookup<OUTPUT_DEVICE, int64_t>)("random"));
+
+ ASSERT_EQ((int32_t)AUDIO_OUTPUT_FLAG_PRIMARY,
+ (lookup<OUTPUT_FLAG, int32_t>)("AUDIO_OUTPUT_FLAG_PRIMARY"));
+ ASSERT_EQ((int32_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER | (int32_t)AUDIO_OUTPUT_FLAG_NON_BLOCKING,
+ (lookup<OUTPUT_FLAG, int32_t>)(
+ "AUDIO_OUTPUT_FLAG_DEEP_BUFFER|AUDIO_OUTPUT_FLAG_NON_BLOCKING"));
+ ASSERT_EQ(0, (lookup<OUTPUT_FLAG, int32_t>)("random"));
+
+ ASSERT_EQ((int32_t)AUDIO_SOURCE_MIC, (lookup<SOURCE_TYPE, int32_t>)("AUDIO_SOURCE_MIC"));
+ ASSERT_EQ((int32_t)AUDIO_SOURCE_DEFAULT, (lookup<SOURCE_TYPE, int32_t>)("random"));
+
+ ASSERT_EQ((int32_t)AUDIO_STREAM_TTS, (lookup<STREAM_TYPE, int32_t>)("AUDIO_STREAM_TTS"));
+ ASSERT_EQ((int32_t)AUDIO_STREAM_DEFAULT, (lookup<STREAM_TYPE, int32_t>)("random"));
+
+ ASSERT_EQ(1, (lookup<THREAD_TYPE, int32_t>)("DIRECT"));
+ ASSERT_EQ(-1, (lookup<THREAD_TYPE, int32_t>)("random"));
+
+ ASSERT_EQ(getAudioTrackTraitsMap().at("static"), (lookup<TRACK_TRAITS, int32_t>)("static"));
+ ASSERT_EQ(0, (lookup<TRACK_TRAITS, int32_t>)("random"));
+
+ ASSERT_EQ((int32_t)AUDIO_USAGE_VOICE_COMMUNICATION,
+ (lookup<USAGE, int32_t>)("AUDIO_USAGE_VOICE_COMMUNICATION"));
+ ASSERT_EQ((int32_t)AUDIO_USAGE_UNKNOWN, (lookup<USAGE, int32_t>)("random"));
+}
+
#if 0
// Stress test code for garbage collection, you need to enable AID_SHELL as trusted to run
// in MediaMetricsService.cpp.