blob: 765a0763d9ffaf426af13962a0a7e0309cf88a56 [file] [log] [blame]
Andy Hung06f3aba2019-12-03 16:36:42 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "AudioAnalytics"
Andy Hung1ea842e2020-05-18 10:47:31 -070019#include <android-base/logging.h>
Andy Hung06f3aba2019-12-03 16:36:42 -080020#include <utils/Log.h>
21
22#include "AudioAnalytics.h"
Andy Hung1ea842e2020-05-18 10:47:31 -070023
Andy Hung73dc2f92021-12-07 21:50:04 -080024#include <aaudio/AAudio.h> // error codes
Andy Hungce9b6632020-04-28 20:15:17 -070025#include <audio_utils/clock.h> // clock conversions
Andy Hung1ea842e2020-05-18 10:47:31 -070026#include <cutils/properties.h>
Andy Hungce9b6632020-04-28 20:15:17 -070027#include <statslog.h> // statsd
jiabinfbf20302021-07-28 22:15:01 +000028#include <system/audio.h>
Andy Hung06f3aba2019-12-03 16:36:42 -080029
Andy Hung1ea842e2020-05-18 10:47:31 -070030#include "AudioTypes.h" // string to int conversions
31#include "MediaMetricsService.h" // package info
32#include "StringUtils.h"
Andy Hungc9b6f8b2021-07-08 10:17:55 -070033#include "ValidateId.h"
Andy Hung1ea842e2020-05-18 10:47:31 -070034
35#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
36
Andy Hunga629bd12020-06-05 16:03:53 -070037namespace android::mediametrics {
Andy Hung1ea842e2020-05-18 10:47:31 -070038
Andy Hunga629bd12020-06-05 16:03:53 -070039// Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
Andy Hunga0a5ad22020-06-12 09:30:34 -070040#define STATSD_ENABLE
Andy Hung1ea842e2020-05-18 10:47:31 -070041
Andy Hunga629bd12020-06-05 16:03:53 -070042#ifdef STATSD_ENABLE
43#define CONDITION(INT_VALUE) (INT_VALUE) // allow value
Andy Hung1ea842e2020-05-18 10:47:31 -070044#else
Andy Hunga629bd12020-06-05 16:03:53 -070045#define CONDITION(INT_VALUE) (int(0)) // mask value since the proto may not be defined yet.
Andy Hung1ea842e2020-05-18 10:47:31 -070046#endif
47
Andy Hunga629bd12020-06-05 16:03:53 -070048// Maximum length of a device name.
Andy Hung3deef2b2020-07-17 12:58:54 -070049// static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
Andy Hung06f3aba2019-12-03 16:36:42 -080050
Andy Hunga629bd12020-06-05 16:03:53 -070051// Transmit Enums to statsd in integer or strings (this must match the atoms.proto)
52static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
53
54// derive types based on integer or strings.
55using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
56using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
57
58// Convert std::string to char *
59template <typename T>
60auto ENUM_EXTRACT(const T& x) {
61 if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
62 return x.c_str();
63 } else {
64 return x;
65 }
66}
67
Andy Hung73dc2f92021-12-07 21:50:04 -080068// The status variable contains status_t codes which are used by
69// the core audio framework. We also consider AAudio status codes.
70//
71// Compare with mediametrics::statusToStatusString
72//
73inline constexpr const char* extendedStatusToStatusString(status_t status) {
74 switch (status) {
75 case BAD_VALUE: // status_t
76 case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
77 case AAUDIO_ERROR_INVALID_FORMAT:
78 case AAUDIO_ERROR_INVALID_RATE:
79 case AAUDIO_ERROR_NULL:
80 case AAUDIO_ERROR_OUT_OF_RANGE:
81 return AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT;
82 case DEAD_OBJECT: // status_t
83 case FAILED_TRANSACTION: // status_t
84 case AAUDIO_ERROR_DISCONNECTED:
85 case AAUDIO_ERROR_INVALID_HANDLE:
86 case AAUDIO_ERROR_NO_SERVICE:
87 return AMEDIAMETRICS_PROP_STATUS_VALUE_IO;
88 case NO_MEMORY: // status_t
89 case AAUDIO_ERROR_NO_FREE_HANDLES:
90 case AAUDIO_ERROR_NO_MEMORY:
91 return AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY;
92 case PERMISSION_DENIED: // status_t
93 return AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY;
94 case INVALID_OPERATION: // status_t
95 case NO_INIT: // status_t
96 case AAUDIO_ERROR_INVALID_STATE:
97 case AAUDIO_ERROR_UNAVAILABLE:
98 case AAUDIO_ERROR_UNIMPLEMENTED:
99 return AMEDIAMETRICS_PROP_STATUS_VALUE_STATE;
100 case WOULD_BLOCK: // status_t
101 case AAUDIO_ERROR_TIMEOUT:
102 case AAUDIO_ERROR_WOULD_BLOCK:
103 return AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT;
104 default:
105 if (status >= 0) return AMEDIAMETRICS_PROP_STATUS_VALUE_OK; // non-negative values "OK"
106 [[fallthrough]]; // negative values are error.
107 case UNKNOWN_ERROR: // status_t
108 return AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN;
109 }
110}
111
Andy Hunga629bd12020-06-05 16:03:53 -0700112static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
113
Andy Hungb18f5062020-06-18 23:10:08 -0700114static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
115
Andy Hung3deef2b2020-07-17 12:58:54 -0700116static constexpr const char * SUPPRESSED = "SUPPRESSED";
117
Andy Hunga629bd12020-06-05 16:03:53 -0700118/*
119 * For logging purposes, we list all of the MediaMetrics atom fields,
120 * which can then be associated with consecutive arguments to the statsd write.
121 */
122
123static constexpr const char * const AudioRecordDeviceUsageFields[] = {
124 "mediametrics_audiorecorddeviceusage_reported", // proto number
125 "devices",
126 "device_names",
127 "device_time_nanos",
128 "encoding",
129 "frame_count",
130 "interval_count",
131 "sample_rate",
132 "flags",
133 "package_name",
134 "selected_device_id",
135 "caller",
136 "source",
Andy Hungcbcfaa22021-02-23 13:54:49 -0800137 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -0700138};
139
140static constexpr const char * const AudioThreadDeviceUsageFields[] = {
141 "mediametrics_audiothreaddeviceusage_reported",
142 "devices",
143 "device_names",
144 "device_time_nanos",
145 "encoding",
146 "frame_count",
147 "interval_count",
148 "sample_rate",
149 "flags",
150 "xruns",
151 "type",
152};
153
154static constexpr const char * const AudioTrackDeviceUsageFields[] = {
155 "mediametrics_audiotrackdeviceusage_reported",
156 "devices",
157 "device_names",
158 "device_time_nanos",
159 "encoding",
160 "frame_count",
161 "interval_count",
162 "sample_rate",
163 "flags",
164 "xruns",
165 "package_name",
166 "device_latency_millis",
167 "device_startup_millis",
168 "device_volume",
169 "selected_device_id",
170 "stream_type",
171 "usage",
172 "content_type",
173 "caller",
174 "traits",
Andy Hungcbcfaa22021-02-23 13:54:49 -0800175 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -0700176};
177
Andy Hung44326582022-01-11 17:27:09 -0800178static constexpr const char * const AudioRecordStatusFields[] {
179 "mediametrics_audiorecordstatus_reported",
180 "status",
181 "debug_message",
182 "status_subcode",
183 "uid",
184 "event",
185 "input_flags",
186 "source",
187 "encoding",
188 "channel_mask",
189 "buffer_frame_count",
190 "sample_rate",
191};
192
Andy Hungb8918b52021-12-14 22:15:40 -0800193static constexpr const char * const AudioTrackStatusFields[] {
194 "mediametrics_audiotrackstatus_reported",
195 "status",
196 "debug_message",
Andy Hungcb40b982022-01-31 20:08:25 -0800197 "status_subcode",
Andy Hungb8918b52021-12-14 22:15:40 -0800198 "uid",
199 "event",
Andy Hungcb40b982022-01-31 20:08:25 -0800200 "output_flags",
Andy Hungb8918b52021-12-14 22:15:40 -0800201 "content_type",
202 "usage",
203 "encoding",
204 "channel_mask",
205 "buffer_frame_count",
206 "sample_rate",
207 "speed",
208 "pitch",
209};
210
Andy Hunga629bd12020-06-05 16:03:53 -0700211static constexpr const char * const AudioDeviceConnectionFields[] = {
212 "mediametrics_audiodeviceconnection_reported",
213 "input_devices",
214 "output_devices",
215 "device_names",
216 "result",
217 "time_to_connect_millis",
218 "connection_count",
219};
220
jiabin92c9a522021-02-12 22:37:42 +0000221static constexpr const char * const AAudioStreamFields[] {
222 "mediametrics_aaudiostream_reported",
jiabin92c9a522021-02-12 22:37:42 +0000223 "path",
224 "direction",
225 "frames_per_burst",
226 "buffer_size",
227 "buffer_capacity",
228 "channel_count",
229 "total_frames_transferred",
230 "perf_mode_requested",
231 "perf_mode_actual",
232 "sharing",
233 "xrun_count",
234 "device_type",
235 "format_app",
236 "format_device",
237 "log_session_id",
jiabinc4c331c2021-03-23 17:11:01 +0000238 "sample_rate",
239 "content_type",
jiabinc8da9032021-04-28 20:42:36 +0000240 "sharing_requested",
jiabin92c9a522021-02-12 22:37:42 +0000241};
242
243/**
244 * printFields is a helper method that prints the fields and corresponding values
245 * in a human readable style.
246 */
247template <size_t N, typename ...Types>
248std::string printFields(const char * const (& fields)[N], Types ... args)
249{
250 std::stringstream ss;
251 ss << " { ";
252 stringutils::fieldPrint(ss, fields, args...);
253 ss << "}";
254 return ss.str();
255}
256
257/**
258 * sendToStatsd is a helper method that sends the arguments to statsd
259 */
260template <typename ...Types>
261int sendToStatsd(Types ... args)
262{
263 int result = 0;
264
265#ifdef STATSD_ENABLE
266 result = android::util::stats_write(args...);
267#endif
268 return result;
269}
jiabin515eb092020-11-18 17:55:52 -0800270
Andy Hunga629bd12020-06-05 16:03:53 -0700271/**
272 * sendToStatsd is a helper method that sends the arguments to statsd
273 * and returns a pair { result, summary_string }.
274 */
275template <size_t N, typename ...Types>
276std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
277{
278 int result = 0;
279 std::stringstream ss;
280
281#ifdef STATSD_ENABLE
282 result = android::util::stats_write(args...);
283 ss << "result:" << result;
284#endif
285 ss << " { ";
286 stringutils::fieldPrint(ss, fields, args...);
287 ss << "}";
288 return { result, ss.str() };
289}
Andy Hung06f3aba2019-12-03 16:36:42 -0800290
Andy Hung5be90c82021-03-30 14:30:20 -0700291AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700292 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700293 , mStatsdLog(statsdLog)
294 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800295{
Andy Hunga629bd12020-06-05 16:03:53 -0700296 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800297 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800298
299 // Add action to save AnalyticsState if audioserver is restarted.
Andy Hungf4eaa462022-03-09 21:53:09 -0800300 // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
301 // as well as TimeCheck events.
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800302 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800303 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
304 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800305 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800306 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungf4eaa462022-03-09 21:53:09 -0800307 mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
308 }));
309 mActions.addAction(
310 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
311 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
312 std::make_shared<AnalyticsActions::Function>(
313 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
314 mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
315 }));
316 mActions.addAction(
317 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
318 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
319 std::make_shared<AnalyticsActions::Function>(
320 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
321 mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
322 }));
323 mActions.addAction(
324 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
325 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
326 std::make_shared<AnalyticsActions::Function>(
327 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
328 mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
Andy Hungea186fa2020-01-09 18:13:15 -0800329 }));
330
jiabin97247ea2021-04-07 00:33:38 +0000331 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800332 mActions.addAction(
333 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
334 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
335 std::make_shared<AnalyticsActions::Function>(
336 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
337 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
338 }));
339
jiabin97247ea2021-04-07 00:33:38 +0000340 // Handle legacy aaudio capture stream statistics
341 mActions.addAction(
342 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
343 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
344 std::make_shared<AnalyticsActions::Function>(
345 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
346 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
347 }));
348
jiabin515eb092020-11-18 17:55:52 -0800349 // Handle mmap aaudio stream statistics
350 mActions.addAction(
351 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
352 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
353 std::make_shared<AnalyticsActions::Function>(
354 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
355 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
356 }));
357
Andy Hungea840382020-05-05 21:50:17 -0700358 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800359 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700360 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
361 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800362 std::make_shared<AnalyticsActions::Function>(
363 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700364 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800365 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700366
367 // Handle device use thread statistics
368 mActions.addAction(
369 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
370 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
371 std::make_shared<AnalyticsActions::Function>(
372 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700373 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700374 }));
375
376 // Handle device use track statistics
377 mActions.addAction(
378 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
379 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
380 std::make_shared<AnalyticsActions::Function>(
381 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700382 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700383 }));
384
Andy Hungea840382020-05-05 21:50:17 -0700385
386 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700387
388 // We track connections (not disconnections) for the time to connect.
389 // TODO: consider BT requests in their A2dp service
390 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
391 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
392 // AudioDeviceBroker.postA2dpActiveDeviceChange
393 mActions.addAction(
394 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700395 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700396 std::make_shared<AnalyticsActions::Function>(
397 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
398 mDeviceConnection.a2dpConnected(item);
399 }));
400 // If audio is active, we expect to see a createAudioPatch after the device is connected.
401 mActions.addAction(
402 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
403 std::string("createAudioPatch"),
404 std::make_shared<AnalyticsActions::Function>(
405 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
406 mDeviceConnection.createPatch(item);
407 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800408
Andy Hungea840382020-05-05 21:50:17 -0700409 // Called from BT service
410 mActions.addAction(
411 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
412 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
413 "." AMEDIAMETRICS_PROP_STATE,
414 "connected",
415 std::make_shared<AnalyticsActions::Function>(
416 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
417 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
418 }));
419
Joey Poomarin52989982020-03-05 17:40:49 +0800420 // Handle power usage
421 mActions.addAction(
422 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
423 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
424 std::make_shared<AnalyticsActions::Function>(
425 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
426 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
427 }));
428
429 mActions.addAction(
430 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
431 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
432 std::make_shared<AnalyticsActions::Function>(
433 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
434 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
435 }));
436
437 mActions.addAction(
438 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
439 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
440 std::make_shared<AnalyticsActions::Function>(
441 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
442 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
443 mAudioPowerUsage.checkMode(item);
444 }));
445
446 mActions.addAction(
447 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
448 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
449 std::make_shared<AnalyticsActions::Function>(
450 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
451 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
452 mAudioPowerUsage.checkVoiceVolume(item);
453 }));
454
455 mActions.addAction(
456 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
457 std::string("createAudioPatch"),
458 std::make_shared<AnalyticsActions::Function>(
459 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
460 mAudioPowerUsage.checkCreatePatch(item);
461 }));
Andy Hunge0d43b42022-08-18 19:20:48 -0700462
463 // Handle Spatializer - these keys are prefixed by "audio.spatializer."
464 mActions.addAction(
465 AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
466 std::monostate{}, /* match any event */
467 std::make_shared<AnalyticsActions::Function>(
468 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
469 mSpatializer.onEvent(item);
470 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800471}
472
473AudioAnalytics::~AudioAnalytics()
474{
475 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700476 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800477}
478
479status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800480 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800481{
Andy Hungea186fa2020-01-09 18:13:15 -0800482 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800483 status_t status = mAnalyticsState->submit(item, isTrusted);
Andy Hung73dc2f92021-12-07 21:50:04 -0800484
485 // Status is selectively authenticated.
486 processStatus(item);
487
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800488 if (status != NO_ERROR) return status; // may not be permitted.
489
490 // Only if the item was successfully submitted (permission)
491 // do we check triggered actions.
Andy Hung73dc2f92021-12-07 21:50:04 -0800492 processActions(item);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800493 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800494}
495
Andy Hung709b91e2020-04-04 14:23:36 -0700496std::pair<std::string, int32_t> AudioAnalytics::dump(
497 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800498{
499 std::stringstream ss;
500 int32_t ll = lines;
501
502 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700503 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700504 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800505 ll -= l;
506 }
507 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800508 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800509 --ll;
510 }
511 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700512 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700513 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800514 ll -= l;
515 }
Joey Poomarin52989982020-03-05 17:40:49 +0800516
517 if (ll > 0 && prefix == nullptr) {
518 auto [s, l] = mAudioPowerUsage.dump(ll);
519 ss << s;
520 ll -= l;
521 }
Andy Hunga629bd12020-06-05 16:03:53 -0700522
Andy Hung06f3aba2019-12-03 16:36:42 -0800523 return { ss.str(), lines - ll };
524}
525
Andy Hung73dc2f92021-12-07 21:50:04 -0800526void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800527{
528 auto actions = mActions.getActionsForItem(item); // internally locked.
529 // Execute actions with no lock held.
530 for (const auto& action : actions) {
531 (*action)(item);
532 }
533}
534
Andy Hung73dc2f92021-12-07 21:50:04 -0800535void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
536{
537 int32_t status;
538 if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
539
540 // Any record with a status will automatically be added to a heat map.
541 // Standard information.
542 const auto key = item->getKey();
543 const auto uid = item->getUid();
544
545 // from audio.track.10 -> prefix = audio.track, suffix = 10
546 // from audio.track.error -> prefix = audio.track, suffix = error
547 const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
548
549 std::string message;
550 item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
551
552 int32_t subCode = 0; // not used
553 (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
554
555 std::string eventStr; // optional
556 item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
557
558 const std::string statusString = extendedStatusToStatusString(status);
559
560 // Add to the heat map - we automatically track every item's status to see
561 // the types of errors and the frequency of errors.
562 mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
Andy Hungb8918b52021-12-14 22:15:40 -0800563
Andy Hung44326582022-01-11 17:27:09 -0800564 // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
565 if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
566 if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
567}
568
569bool AudioAnalytics::reportAudioRecordStatus(
570 const std::shared_ptr<const mediametrics::Item>& item,
571 const std::string& key, const std::string& eventStr,
572 const std::string& statusString, uid_t uid, const std::string& message,
573 int32_t subCode) const
574{
Andy Hungb8918b52021-12-14 22:15:40 -0800575 // Note that the prefixes often end with a '.' so we use startsWith.
Andy Hung44326582022-01-11 17:27:09 -0800576 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
577 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
578 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
579
580 // currently we only send create status events.
581 const int32_t event = android::util::
582 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
583
584 // The following fields should all be present in a create event.
585 std::string flagsStr;
586 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
587 "%s: %s missing %s field", __func__,
588 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
589 const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
590
591 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
592
593 std::string sourceStr;
594 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
595 "%s: %s missing %s field",
596 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
597 const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
598
599 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
600
601 std::string encodingStr;
602 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
603 "%s: %s missing %s field",
604 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
605 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
606
607 int32_t channelMask = 0;
608 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
609 "%s: %s missing %s field",
610 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
611 int32_t frameCount = 0;
612 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
613 "%s: %s missing %s field",
614 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
615 int32_t sampleRate = 0;
616 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
617 "%s: %s missing %s field",
618 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
619
620 const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
621 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
622 , atom_status
623 , message.c_str()
624 , subCode
625 , uid
626 , event
627 , flags
628 , source
629 , encoding
630 , (int64_t)channelMask
631 , frameCount
632 , sampleRate
633 );
634 ALOGV("%s: statsd %s", __func__, str.c_str());
635 mStatsdLog->log(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
636 return true;
637 }
638 return false;
639}
640
641bool AudioAnalytics::reportAudioTrackStatus(
642 const std::shared_ptr<const mediametrics::Item>& item,
643 const std::string& key, const std::string& eventStr,
644 const std::string& statusString, uid_t uid, const std::string& message,
645 int32_t subCode) const
646{
647 // Note that the prefixes often end with a '.' so we use startsWith.
648 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
649 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
Andy Hungb8918b52021-12-14 22:15:40 -0800650 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
651
652 // currently we only send create status events.
Andy Hungcb40b982022-01-31 20:08:25 -0800653 const int32_t event = android::util::
654 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
Andy Hungb8918b52021-12-14 22:15:40 -0800655
656 // The following fields should all be present in a create event.
657 std::string flagsStr;
658 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
659 "%s: %s missing %s field",
660 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
661 const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
662
663 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
664
665 std::string contentTypeStr;
666 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
667 "%s: %s missing %s field",
668 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
669 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
670
671 std::string usageStr;
672 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
673 "%s: %s missing %s field",
674 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
675 const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
676
677 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
678
679 std::string encodingStr;
680 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
681 "%s: %s missing %s field",
682 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
683 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
684
685 int32_t channelMask = 0;
686 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
687 "%s: %s missing %s field",
688 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
689 int32_t frameCount = 0;
690 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
691 "%s: %s missing %s field",
692 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
693 int32_t sampleRate = 0;
694 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
695 "%s: %s missing %s field",
696 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
697 double speed = 0.f; // default is 1.f
698 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
699 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800700 __func__,
701 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
Andy Hungb8918b52021-12-14 22:15:40 -0800702 double pitch = 0.f; // default is 1.f
703 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
704 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800705 __func__,
706 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
Andy Hungb8918b52021-12-14 22:15:40 -0800707 const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
708 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
709 , atom_status
710 , message.c_str()
711 , subCode
712 , uid
713 , event
714 , flags
715 , contentType
716 , usage
717 , encoding
718 , (int64_t)channelMask
719 , frameCount
720 , sampleRate
721 , (float)speed
722 , (float)pitch
723 );
724 ALOGV("%s: statsd %s", __func__, str.c_str());
725 mStatsdLog->log(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800726 return true;
Andy Hungb8918b52021-12-14 22:15:40 -0800727 }
Andy Hung44326582022-01-11 17:27:09 -0800728 return false;
Andy Hung73dc2f92021-12-07 21:50:04 -0800729}
730
Andy Hungea186fa2020-01-09 18:13:15 -0800731// HELPER METHODS
732
733std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
734{
735 int32_t threadId_int32{};
736 if (mAnalyticsState->timeMachine().get(
737 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
738 return {};
739 }
740 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
741}
742
Andy Hungce9b6632020-04-28 20:15:17 -0700743// DeviceUse helper class.
744void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700745 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700746 const std::string& key = item->getKey();
747 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700748 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
749 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
750 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700751 - 1);
752 // deliver statistics
753 int64_t deviceTimeNs = 0;
754 mAudioAnalytics.mAnalyticsState->timeMachine().get(
755 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
756 std::string encoding;
757 mAudioAnalytics.mAnalyticsState->timeMachine().get(
758 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
759 int32_t frameCount = 0;
760 mAudioAnalytics.mAnalyticsState->timeMachine().get(
761 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700762 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700763 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700764 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700765 int32_t intervalCount = 0;
766 mAudioAnalytics.mAnalyticsState->timeMachine().get(
767 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700768 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700769 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700770 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700771 int32_t sampleRate = 0;
772 mAudioAnalytics.mAnalyticsState->timeMachine().get(
773 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700774 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700775 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700776 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700777
Andy Hungea840382020-05-05 21:50:17 -0700778 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700779 // Accumulate the bit flags for input and output devices.
780 std::stringstream oss;
781 long_enum_type_t outputDeviceBits{};
782 { // compute outputDevices
783 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700784 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700785 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
786 oss << device;
787 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700788 }
789 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700790 const std::string outputDevices = oss.str();
791
792 std::stringstream iss;
793 long_enum_type_t inputDeviceBits{};
794 { // compute inputDevices
795 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
796 for (const auto& [device, addr] : devaddrvec) {
797 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
798 iss << device;
799 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
800 }
801 }
802 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700803
804 // Get connected device name if from bluetooth.
805 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700806
807 std::string inputDeviceNames; // not filled currently.
808 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700809 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
810 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700811 outputDeviceNames = SUPPRESSED;
812#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700813 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700814 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700815 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700816 stringutils::replace(outputDeviceNames, "|", '?');
817 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
818 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
819 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700820#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700821 }
822
Andy Hungea840382020-05-05 21:50:17 -0700823 switch (itemType) {
824 case RECORD: {
825 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700826 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
827 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700828
Andy Hungea840382020-05-05 21:50:17 -0700829 std::string packageName;
830 int64_t versionCode = 0;
831 int32_t uid = -1;
832 mAudioAnalytics.mAnalyticsState->timeMachine().get(
833 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
834 if (uid != -1) {
835 std::tie(packageName, versionCode) =
836 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
837 }
838
839 int32_t selectedDeviceId = 0;
840 mAudioAnalytics.mAnalyticsState->timeMachine().get(
841 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
842 std::string source;
843 mAudioAnalytics.mAnalyticsState->timeMachine().get(
844 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800845 // Android S
846 std::string logSessionId;
847 mAudioAnalytics.mAnalyticsState->timeMachine().get(
848 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700849
Andy Hung1ea842e2020-05-18 10:47:31 -0700850 const auto callerNameForStats =
851 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
852 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
853 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
854 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800855 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700856 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700857
Andy Hunga629bd12020-06-05 16:03:53 -0700858 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700859 << " id:" << id
860 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700861 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700862 << " deviceTimeNs:" << deviceTimeNs
863 << " encoding:" << encoding << "(" << encodingForStats
864 << ") frameCount:" << frameCount
865 << " intervalCount:" << intervalCount
866 << " sampleRate:" << sampleRate
867 << " flags:" << flags << "(" << flagsForStats
868 << ") packageName:" << packageName
869 << " selectedDeviceId:" << selectedDeviceId
870 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800871 << ") source:" << source << "(" << sourceForStats
872 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
873 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700874 if (clientCalled // only log if client app called AudioRecord.
875 && mAudioAnalytics.mDeliverStatistics) {
876 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
877 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700878 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700879 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700880 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700881 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700882 , frameCount
883 , intervalCount
884 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700885 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700886
887 , packageName.c_str()
888 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700889 , ENUM_EXTRACT(callerNameForStats)
890 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800891 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700892 );
Andy Hunga629bd12020-06-05 16:03:53 -0700893 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700894 mAudioAnalytics.mStatsdLog->log(
895 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700896 }
Andy Hungea840382020-05-05 21:50:17 -0700897 } break;
898 case THREAD: {
899 std::string type;
900 mAudioAnalytics.mAnalyticsState->timeMachine().get(
901 key, AMEDIAMETRICS_PROP_TYPE, &type);
902 int32_t underrun = 0; // zero for record types
903 mAudioAnalytics.mAnalyticsState->timeMachine().get(
904 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700905
906 const bool isInput = types::isInputThreadType(type);
907 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
908 const auto flagsForStats =
909 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
910 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
911 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
912
Andy Hunga629bd12020-06-05 16:03:53 -0700913 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700914 << " id:" << id
915 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
916 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700917 << ") inputDeviceNames:" << inputDeviceNames
918 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700919 << " deviceTimeNs:" << deviceTimeNs
920 << " encoding:" << encoding << "(" << encodingForStats
921 << ") frameCount:" << frameCount
922 << " intervalCount:" << intervalCount
923 << " sampleRate:" << sampleRate
924 << " underrun:" << underrun
925 << " flags:" << flags << "(" << flagsForStats
926 << ") type:" << type << "(" << typeForStats
927 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700928 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700929 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
930 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
931 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
932 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700933 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700934 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700935 , frameCount
936 , intervalCount
937 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700938 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700939 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700940 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700941 );
Andy Hunga629bd12020-06-05 16:03:53 -0700942 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700943 mAudioAnalytics.mStatsdLog->log(
944 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700945 }
Andy Hungea840382020-05-05 21:50:17 -0700946 } break;
947 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700948 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700949 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
950 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
951
Andy Hungce9b6632020-04-28 20:15:17 -0700952 std::string contentType;
953 mAudioAnalytics.mAnalyticsState->timeMachine().get(
954 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
955 double deviceLatencyMs = 0.;
956 mAudioAnalytics.mAnalyticsState->timeMachine().get(
957 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
958 double deviceStartupMs = 0.;
959 mAudioAnalytics.mAnalyticsState->timeMachine().get(
960 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
961 double deviceVolume = 0.;
962 mAudioAnalytics.mAnalyticsState->timeMachine().get(
963 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
964 std::string packageName;
965 int64_t versionCode = 0;
966 int32_t uid = -1;
967 mAudioAnalytics.mAnalyticsState->timeMachine().get(
968 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
969 if (uid != -1) {
970 std::tie(packageName, versionCode) =
971 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
972 }
973 double playbackPitch = 0.;
974 mAudioAnalytics.mAnalyticsState->timeMachine().get(
975 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
976 double playbackSpeed = 0.;
977 mAudioAnalytics.mAnalyticsState->timeMachine().get(
978 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
979 int32_t selectedDeviceId = 0;
980 mAudioAnalytics.mAnalyticsState->timeMachine().get(
981 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700982 std::string streamType;
983 mAudioAnalytics.mAnalyticsState->timeMachine().get(
984 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700985 std::string traits;
986 mAudioAnalytics.mAnalyticsState->timeMachine().get(
987 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700988 int32_t underrun = 0;
989 mAudioAnalytics.mAnalyticsState->timeMachine().get(
990 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700991 std::string usage;
992 mAudioAnalytics.mAnalyticsState->timeMachine().get(
993 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800994 // Android S
995 std::string logSessionId;
996 mAudioAnalytics.mAnalyticsState->timeMachine().get(
997 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700998
Andy Hung1ea842e2020-05-18 10:47:31 -0700999 const auto callerNameForStats =
1000 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
1001 const auto contentTypeForStats =
1002 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
1003 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
1004 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
1005 const auto streamTypeForStats =
1006 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001007 const auto traitsForStats =
1008 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -07001009 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001010 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -07001011 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -07001012
Andy Hunga629bd12020-06-05 16:03:53 -07001013 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001014 << " id:" << id
1015 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001016 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -07001017 << " deviceTimeNs:" << deviceTimeNs
1018 << " encoding:" << encoding << "(" << encodingForStats
1019 << ") frameCount:" << frameCount
1020 << " intervalCount:" << intervalCount
1021 << " sampleRate:" << sampleRate
1022 << " underrun:" << underrun
1023 << " flags:" << flags << "(" << flagsForStats
1024 << ") callerName:" << callerName << "(" << callerNameForStats
1025 << ") contentType:" << contentType << "(" << contentTypeForStats
1026 << ") deviceLatencyMs:" << deviceLatencyMs
1027 << " deviceStartupMs:" << deviceStartupMs
1028 << " deviceVolume:" << deviceVolume
1029 << " packageName:" << packageName
1030 << " playbackPitch:" << playbackPitch
1031 << " playbackSpeed:" << playbackSpeed
1032 << " selectedDeviceId:" << selectedDeviceId
1033 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -07001034 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001035 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -08001036 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001037 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -07001038 if (clientCalled // only log if client app called AudioTracks
1039 && mAudioAnalytics.mDeliverStatistics) {
1040 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
1041 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001042 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001043 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001044 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -07001045 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001046 , frameCount
1047 , intervalCount
1048 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -07001049 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001050 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -07001051 , packageName.c_str()
1052 , (float)deviceLatencyMs
1053 , (float)deviceStartupMs
1054 , (float)deviceVolume
1055 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -07001056 , ENUM_EXTRACT(streamTypeForStats)
1057 , ENUM_EXTRACT(usageForStats)
1058 , ENUM_EXTRACT(contentTypeForStats)
1059 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -07001060 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -08001061 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001062 );
Andy Hunga629bd12020-06-05 16:03:53 -07001063 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001064 mAudioAnalytics.mStatsdLog->log(
1065 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -07001066 }
Andy Hungea840382020-05-05 21:50:17 -07001067 } break;
Andy Hungce9b6632020-04-28 20:15:17 -07001068 }
1069
1070 // Report this as needed.
1071 if (isBluetooth) {
1072 // report this for Bluetooth
1073 }
1074}
1075
1076// DeviceConnection helper class.
1077void AudioAnalytics::DeviceConnection::a2dpConnected(
1078 const std::shared_ptr<const android::mediametrics::Item> &item) {
1079 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -07001080 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -07001081 {
1082 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001083 mA2dpConnectionServiceNs = atNs;
1084 ++mA2dpConnectionServices;
1085
1086 if (mA2dpConnectionRequestNs == 0) {
1087 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1088 }
1089 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -07001090 }
1091 std::string name;
1092 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001093 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1094 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -07001095}
1096
1097void AudioAnalytics::DeviceConnection::createPatch(
1098 const std::shared_ptr<const android::mediametrics::Item> &item) {
1099 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001100 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -07001101 const std::string& key = item->getKey();
1102 std::string outputDevices;
1103 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -07001104 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -07001105 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -07001106 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -07001107 if (mA2dpConnectionRequestNs == 0) {
1108 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -07001109 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -07001110 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -07001111 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -07001112 }
Andy Hung1ea842e2020-05-18 10:47:31 -07001113
Andy Hungea840382020-05-05 21:50:17 -07001114 mA2dpConnectionRequestNs = 0;
1115 mA2dpConnectionServiceNs = 0;
1116 ++mA2dpConnectionSuccesses;
1117
Andy Hungc14ee142021-03-10 16:39:02 -08001118 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -07001119
1120 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1121 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1122
Andy Hunga629bd12020-06-05 16:03:53 -07001123 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001124 << " A2DP SUCCESS"
1125 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001126 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -07001127 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -07001128 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -07001129 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -07001130
1131 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1132 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001133 , ENUM_EXTRACT(inputDeviceBits)
1134 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001135 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001136 , types::DEVICE_CONNECTION_RESULT_SUCCESS
1137 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -07001138 , /* connection_count */ 1
1139 );
Andy Hunga629bd12020-06-05 16:03:53 -07001140 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001141 mAudioAnalytics.mStatsdLog->log(
1142 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001143 }
Andy Hungce9b6632020-04-28 20:15:17 -07001144 }
1145}
1146
Andy Hungea840382020-05-05 21:50:17 -07001147// Called through AudioManager when the BT service wants to enable
1148void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1149 const std::shared_ptr<const android::mediametrics::Item> &item) {
1150 const int64_t atNs = item->getTimestamp();
1151 const std::string& key = item->getKey();
1152 std::string state;
1153 item->get(AMEDIAMETRICS_PROP_STATE, &state);
1154 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -07001155
1156 std::string name;
1157 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001158 {
1159 std::lock_guard l(mLock);
1160 mA2dpConnectionRequestNs = atNs;
1161 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -07001162 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -07001163 }
Andy Hunga629bd12020-06-05 16:03:53 -07001164 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1165 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -07001166 // TODO: attempt to cancel a timed event, rather than let it expire.
1167 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1168}
1169
Andy Hungce9b6632020-04-28 20:15:17 -07001170void AudioAnalytics::DeviceConnection::expire() {
1171 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001172 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -07001173
Andy Hung1ea842e2020-05-18 10:47:31 -07001174 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -07001175 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1176 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1177
Andy Hungea840382020-05-05 21:50:17 -07001178 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -07001179 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -07001180
Andy Hunga629bd12020-06-05 16:03:53 -07001181 LOG(LOG_LEVEL) << "A2DP CANCEL"
1182 << " outputDevices:" << outputDeviceBits
1183 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001184 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001185 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1186 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001187 , ENUM_EXTRACT(inputDeviceBits)
1188 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001189 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001190 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -07001191 , /* connection_time_ms */ 0.f
1192 , /* connection_count */ 1
1193 );
Andy Hunga629bd12020-06-05 16:03:53 -07001194 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001195 mAudioAnalytics.mStatsdLog->log(
1196 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001197 }
Andy Hungea840382020-05-05 21:50:17 -07001198 return;
1199 }
1200
1201 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1202 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -07001203 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -07001204 mA2dpConnectionRequestNs = 0;
1205 mA2dpConnectionServiceNs = 0;
1206 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -07001207
Andy Hunga629bd12020-06-05 16:03:53 -07001208 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1209 << " outputDevices:" << outputDeviceBits
1210 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001211 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001212 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1213 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001214 , ENUM_EXTRACT(inputDeviceBits)
1215 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001216 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001217 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -07001218 , /* connection_time_ms */ 0.f
1219 , /* connection_count */ 1
1220 );
Andy Hunga629bd12020-06-05 16:03:53 -07001221 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001222 mAudioAnalytics.mStatsdLog->log(
1223 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001224 }
Andy Hungce9b6632020-04-28 20:15:17 -07001225}
1226
jiabin515eb092020-11-18 17:55:52 -08001227void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1228 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1229 const std::string& key = item->getKey();
1230
jiabin515eb092020-11-18 17:55:52 -08001231 std::string directionStr;
1232 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1233 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1234 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1235
1236 int32_t framesPerBurst = -1;
1237 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1238 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1239
1240 int32_t bufferSizeInFrames = -1;
1241 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1242 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1243
1244 int32_t bufferCapacityInFrames = -1;
1245 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1246 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1247
1248 int32_t channelCount = -1;
1249 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1250 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +00001251 if (channelCount == -1) {
1252 // Try to get channel count from channel mask. From the legacy path,
1253 // only channel mask are logged.
1254 int32_t channelMask = 0;
1255 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1256 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1257 if (channelMask != 0) {
1258 switch (direction) {
1259 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001260 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001261 break;
1262 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001263 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001264 break;
1265 default:
1266 ALOGW("Invalid direction %d", direction);
1267 }
1268 }
1269 }
jiabin515eb092020-11-18 17:55:52 -08001270
1271 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +00001272 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1273 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -08001274
1275 std::string perfModeRequestedStr;
1276 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1277 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1278 const auto perfModeRequested =
1279 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1280
jiabin97247ea2021-04-07 00:33:38 +00001281 std::string perfModeActualStr;
1282 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1283 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1284 const auto perfModeActual =
1285 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001286
jiabinc8da9032021-04-28 20:42:36 +00001287 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -08001288 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001289 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1290 const auto sharingModeActual =
1291 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001292
1293 int32_t xrunCount = -1;
1294 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1295 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1296
jiabin92c9a522021-02-12 22:37:42 +00001297 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001298 // TODO: only routed device id is logged, but no device type
1299
jiabin97247ea2021-04-07 00:33:38 +00001300 std::string formatAppStr;
1301 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001302 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001303 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001304
1305 std::string formatDeviceStr;
1306 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1307 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1308 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1309
jiabin92c9a522021-02-12 22:37:42 +00001310 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001311 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1312 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001313
jiabinc4c331c2021-03-23 17:11:01 +00001314 int32_t sampleRate = 0;
1315 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1316 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1317
1318 std::string contentTypeStr;
1319 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1320 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1321 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1322
jiabinc8da9032021-04-28 20:42:36 +00001323 std::string sharingModeRequestedStr;
1324 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1325 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1326 const auto sharingModeRequested =
1327 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1328
jiabin515eb092020-11-18 17:55:52 -08001329 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001330 << " path:" << path
1331 << " direction:" << direction << "(" << directionStr << ")"
1332 << " frames_per_burst:" << framesPerBurst
1333 << " buffer_size:" << bufferSizeInFrames
1334 << " buffer_capacity:" << bufferCapacityInFrames
1335 << " channel_count:" << channelCount
1336 << " total_frames_transferred:" << totalFramesTransferred
1337 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001338 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001339 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001340 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001341 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001342 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001343 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001344 << " log_session_id: " << logSessionId
1345 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001346 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1347 << " sharing_requested:" << sharingModeRequested
1348 << "(" << sharingModeRequestedStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001349
jiabin92c9a522021-02-12 22:37:42 +00001350 if (mAudioAnalytics.mDeliverStatistics) {
1351 android::util::BytesField bf_serialized(
1352 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1353 const auto result = sendToStatsd(
1354 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001355 , path
1356 , direction
1357 , framesPerBurst
1358 , bufferSizeInFrames
1359 , bufferCapacityInFrames
1360 , channelCount
1361 , totalFramesTransferred
1362 , perfModeRequested
1363 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001364 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001365 , xrunCount
1366 , bf_serialized
1367 , formatApp
1368 , formatDevice
1369 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001370 , sampleRate
1371 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001372 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001373 );
1374 std::stringstream ss;
1375 ss << "result:" << result;
1376 const auto fieldsStr = printFields(AAudioStreamFields,
1377 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001378 , path
1379 , direction
1380 , framesPerBurst
1381 , bufferSizeInFrames
1382 , bufferCapacityInFrames
1383 , channelCount
1384 , totalFramesTransferred
1385 , perfModeRequested
1386 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001387 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001388 , xrunCount
1389 , serializedDeviceTypes.c_str()
1390 , formatApp
1391 , formatDevice
1392 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001393 , sampleRate
1394 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001395 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001396 );
1397 ss << " " << fieldsStr;
1398 std::string str = ss.str();
1399 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001400 mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001401 }
jiabin515eb092020-11-18 17:55:52 -08001402}
1403
Andy Hungf4eaa462022-03-09 21:53:09 -08001404// Create new state, typically occurs after an AudioFlinger ctor event.
1405void AudioAnalytics::newState()
1406{
1407 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
1408 *mAnalyticsState.get()));
1409 // Note: get returns shared_ptr temp, whose lifetime is extended
1410 // to end of full expression.
1411 mAnalyticsState->clear(); // TODO: filter the analytics state.
1412 // Perhaps report this.
1413
1414 // Set up a timer to expire the previous audio state to save space.
1415 // Use the transaction log size as a cookie to see if it is the
1416 // same as before. A benign race is possible where a state is cleared early.
1417 const size_t size = mPreviousAnalyticsState->transactionLog().size();
1418 mTimedAction.postIn(
1419 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
1420 if (mPreviousAnalyticsState->transactionLog().size() == size) {
1421 ALOGD("expiring previous audio state after %d seconds.",
1422 PREVIOUS_STATE_EXPIRE_SEC);
1423 mPreviousAnalyticsState->clear(); // removes data from the state.
1424 }
1425 });
1426}
1427
1428void AudioAnalytics::Health::onAudioServerStart(Module module,
1429 const std::shared_ptr<const android::mediametrics::Item> &item)
1430{
1431 const auto nowTime = std::chrono::system_clock::now();
1432 if (module == Module::AUDIOFLINGER) {
1433 {
1434 std::lock_guard lg(mLock);
1435 // reset state on AudioFlinger construction.
1436 // AudioPolicy is created after AudioFlinger.
1437 mAudioFlingerCtorTime = nowTime;
1438 mSimpleLog.log("AudioFlinger ctor");
1439 }
1440 mAudioAnalytics.newState();
1441 return;
1442 }
1443 if (module == Module::AUDIOPOLICY) {
1444 // A start event occurs when audioserver
1445 //
1446 // (1) Starts the first time
1447 // (2) Restarts because of the TimeCheck watchdog
1448 // (3) Restarts not because of the TimeCheck watchdog.
1449 int64_t executionTimeNs = 0;
1450 (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
1451 const float loadTimeMs = executionTimeNs * 1e-6f;
1452 std::lock_guard lg(mLock);
1453 const int64_t restarts = mStartCount;
1454 if (mStopCount == mStartCount) {
1455 mAudioPolicyCtorTime = nowTime;
1456 ++mStartCount;
1457 if (mStopCount == 0) {
1458 // (1) First time initialization.
1459 ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
1460 __func__, item->getKey().c_str(), loadTimeMs);
1461 mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
1462 } else {
1463 // (2) Previous failure caught due to TimeCheck. We know how long restart takes.
1464 const float restartMs =
1465 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1466 mAudioFlingerCtorTime - mStopTime).count();
1467 ALOGW("%s: (key=%s) AudioPolicy ctor, "
1468 "restarts:%lld restartMs:%f loadTimeMs:%f",
1469 __func__, item->getKey().c_str(),
1470 (long long)restarts, restartMs, loadTimeMs);
1471 mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
1472 (long long)restarts, restartMs, loadTimeMs);
1473 }
1474 } else {
1475 // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
1476 // However we can estimate the uptime from the delta time from previous ctor.
1477 const float uptimeMs =
1478 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1479 nowTime - mAudioFlingerCtorTime).count();
1480 mStopCount = mStartCount;
1481 mAudioPolicyCtorTime = nowTime;
1482 ++mStartCount;
1483
1484 ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
1485 "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
1486 __func__, item->getKey().c_str(),
1487 (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
1488 mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
1489 "restarts:%lld uptimeMs:%f loadTimeMs:%f",
1490 (long long)restarts, uptimeMs, loadTimeMs);
1491 }
1492 }
1493}
1494
1495void AudioAnalytics::Health::onAudioServerTimeout(Module module,
1496 const std::shared_ptr<const android::mediametrics::Item> &item)
1497{
1498 std::string moduleName = getModuleName(module);
1499 int64_t methodCode{};
1500 std::string methodName;
1501 (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
1502 (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
1503
1504 std::lock_guard lg(mLock);
1505 if (mStopCount >= mStartCount) {
1506 ALOGD("%s: (key=%s) %s timeout %s(%lld) "
1507 "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
1508 __func__, item->getKey().c_str(), moduleName.c_str(),
1509 methodName.c_str(), (long long)methodCode,
1510 (long long)mStopCount, (long long)mStartCount);
1511 return;
1512 }
1513
1514 const int64_t restarts = mStartCount - 1;
1515 ++mStopCount;
1516 mStopTime = std::chrono::system_clock::now();
1517 const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1518 mStopTime - mAudioFlingerCtorTime).count();
1519 ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1520 __func__, item->getKey().c_str(), moduleName.c_str(),
1521 methodName.c_str(), (long long)methodCode,
1522 (long long)restarts, uptimeMs);
1523 mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1524 moduleName.c_str(), methodName.c_str(), (long long)methodCode,
1525 (long long)restarts, uptimeMs);
1526}
1527
1528std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
1529 int32_t lines, const char *prefix) const
1530{
1531 std::lock_guard lg(mLock);
1532 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1533 size_t n = std::count(s.begin(), s.end(), '\n');
1534 return { s, n };
1535}
1536
Andy Hunge0d43b42022-08-18 19:20:48 -07001537void AudioAnalytics::Spatializer::onEvent(
1538 const std::shared_ptr<const android::mediametrics::Item> &item)
1539{
1540 const auto key = item->getKey();
1541
1542 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;
1543
1544 const std::string suffix =
1545 key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);
1546
1547 std::string eventStr; // optional - find the actual event string.
1548 (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
1549
1550 const size_t delim = suffix.find('.'); // note could use split.
1551 if (delim == suffix.npos) {
1552 // on create with suffix == "0" for the first spatializer effect.
1553
1554 std::string headTrackingModes;
1555 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);
1556
1557 std::string levels;
1558 (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);
1559
1560 std::string modes;
1561 (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);
1562
1563 int32_t channelMask = 0;
1564 (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1565
1566 LOG(LOG_LEVEL) << "key:" << key
1567 << " headTrackingModes:" << headTrackingModes
1568 << " levels:" << levels
1569 << " modes:" << modes
1570 << " channelMask:" << channelMask
1571 ;
1572
1573 const std::vector<int32_t> headTrackingModesVector =
1574 types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
1575 const std::vector<int32_t> levelsVector =
1576 types::vectorFromMap(levels, types::getSpatializerLevelMap());
1577 const std::vector<int32_t> modesVector =
1578 types::vectorFromMap(modes, types::getSpatializerModeMap());
1579
1580 // TODO: send to statsd
1581
1582 std::lock_guard lg(mLock);
1583 mSimpleLog.log("%s suffix: %s item: %s",
1584 __func__, suffix.c_str(), item->toString().c_str());
1585 } else {
1586 std::string subtype = suffix.substr(0, delim);
1587 if (subtype != "device") return; // not a device.
1588
1589 std::string deviceType = suffix.substr(std::size("device.") - 1);
1590
1591 std::string enabled;
1592 (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
1593 std::string hasHeadTracker;
1594 (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
1595 std::string headTrackerEnabled;
1596 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);
1597
1598 std::lock_guard lg(mLock);
1599
1600 // Validate from our cached state
1601 DeviceState& deviceState = mDeviceStateMap[deviceType];
1602
1603 if (!enabled.empty()) {
1604 if (enabled != deviceState.enabled) {
1605 deviceState.enabled = enabled;
1606 const bool enabledStatsd = enabled == "true";
1607 // TODO: send to statsd
1608 (void)mAudioAnalytics;
1609 (void)enabledStatsd;
1610 }
1611 }
1612 if (!hasHeadTracker.empty()) {
1613 if (hasHeadTracker != deviceState.hasHeadTracker) {
1614 deviceState.hasHeadTracker = hasHeadTracker;
1615 const bool supportedStatsd = hasHeadTracker == "true";
1616 // TODO: send to statsd
1617 (void)supportedStatsd;
1618 }
1619 }
1620 if (!headTrackerEnabled.empty()) {
1621 if (headTrackerEnabled != deviceState.headTrackerEnabled) {
1622 deviceState.headTrackerEnabled = headTrackerEnabled;
1623 const bool enabledStatsd = headTrackerEnabled == "true";
1624 // TODO: send to statsd
1625 (void)enabledStatsd;
1626 }
1627 }
1628 mSimpleLog.log("%s deviceType: %s item: %s",
1629 __func__, deviceType.c_str(), item->toString().c_str());
1630 }
1631}
1632
1633std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
1634 int32_t lines, const char *prefix) const
1635{
1636 std::lock_guard lg(mLock);
1637 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1638 size_t n = std::count(s.begin(), s.end(), '\n');
1639 return { s, n };
1640}
Andy Hungf4eaa462022-03-09 21:53:09 -08001641
Andy Hung3ab1b322020-05-18 10:47:31 -07001642} // namespace android::mediametrics