blob: 6138d32e30174b7971b1fd3f5d66165e6863bdf2 [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"
19#include <utils/Log.h>
20
21#include "AudioAnalytics.h"
Andy Hungce9b6632020-04-28 20:15:17 -070022#include "MediaMetricsService.h" // package info
23#include <audio_utils/clock.h> // clock conversions
24#include <statslog.h> // statsd
Andy Hung06f3aba2019-12-03 16:36:42 -080025
Andy Hungce9b6632020-04-28 20:15:17 -070026// Enable for testing of delivery to statsd
27// #define STATSD
Andy Hung06f3aba2019-12-03 16:36:42 -080028
29namespace android::mediametrics {
30
31AudioAnalytics::AudioAnalytics()
32{
33 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -080034
35 // Add action to save AnalyticsState if audioserver is restarted.
36 // This triggers on an item of "audio.flinger"
37 // with a property "event" set to "AudioFlinger" (the constructor).
38 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -080039 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
40 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -080041 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -080042 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
43 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -080044 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
45 *mAnalyticsState.get()));
46 // Note: get returns shared_ptr temp, whose lifetime is extended
47 // to end of full expression.
48 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -080049 // Perhaps report this.
50 }));
51
Andy Hungea840382020-05-05 21:50:17 -070052 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -080053 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -070054 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
55 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -080056 std::make_shared<AnalyticsActions::Function>(
57 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -070058 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -080059 }));
Andy Hungce9b6632020-04-28 20:15:17 -070060
61 // Handle device use thread statistics
62 mActions.addAction(
63 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
64 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
65 std::make_shared<AnalyticsActions::Function>(
66 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -070067 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -070068 }));
69
70 // Handle device use track statistics
71 mActions.addAction(
72 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
73 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
74 std::make_shared<AnalyticsActions::Function>(
75 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -070076 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -070077 }));
78
Andy Hungea840382020-05-05 21:50:17 -070079
80 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -070081
82 // We track connections (not disconnections) for the time to connect.
83 // TODO: consider BT requests in their A2dp service
84 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
85 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
86 // AudioDeviceBroker.postA2dpActiveDeviceChange
87 mActions.addAction(
88 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -070089 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -070090 std::make_shared<AnalyticsActions::Function>(
91 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
92 mDeviceConnection.a2dpConnected(item);
93 }));
94 // If audio is active, we expect to see a createAudioPatch after the device is connected.
95 mActions.addAction(
96 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
97 std::string("createAudioPatch"),
98 std::make_shared<AnalyticsActions::Function>(
99 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
100 mDeviceConnection.createPatch(item);
101 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800102
Andy Hungea840382020-05-05 21:50:17 -0700103 // Called from BT service
104 mActions.addAction(
105 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
106 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
107 "." AMEDIAMETRICS_PROP_STATE,
108 "connected",
109 std::make_shared<AnalyticsActions::Function>(
110 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
111 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
112 }));
113
Joey Poomarin52989982020-03-05 17:40:49 +0800114 // Handle power usage
115 mActions.addAction(
116 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
117 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
118 std::make_shared<AnalyticsActions::Function>(
119 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
120 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
121 }));
122
123 mActions.addAction(
124 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
125 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
126 std::make_shared<AnalyticsActions::Function>(
127 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
128 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
129 }));
130
131 mActions.addAction(
132 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
133 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
134 std::make_shared<AnalyticsActions::Function>(
135 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
136 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
137 mAudioPowerUsage.checkMode(item);
138 }));
139
140 mActions.addAction(
141 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
142 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
143 std::make_shared<AnalyticsActions::Function>(
144 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
145 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
146 mAudioPowerUsage.checkVoiceVolume(item);
147 }));
148
149 mActions.addAction(
150 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
151 std::string("createAudioPatch"),
152 std::make_shared<AnalyticsActions::Function>(
153 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
154 mAudioPowerUsage.checkCreatePatch(item);
155 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800156}
157
158AudioAnalytics::~AudioAnalytics()
159{
160 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700161 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800162}
163
164status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800165 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800166{
Andy Hungea186fa2020-01-09 18:13:15 -0800167 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800168 status_t status = mAnalyticsState->submit(item, isTrusted);
169 if (status != NO_ERROR) return status; // may not be permitted.
170
171 // Only if the item was successfully submitted (permission)
172 // do we check triggered actions.
173 checkActions(item);
174 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800175}
176
Andy Hung709b91e2020-04-04 14:23:36 -0700177std::pair<std::string, int32_t> AudioAnalytics::dump(
178 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800179{
180 std::stringstream ss;
181 int32_t ll = lines;
182
183 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700184 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700185 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800186 ll -= l;
187 }
188 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800189 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800190 --ll;
191 }
192 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700193 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700194 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800195 ll -= l;
196 }
Joey Poomarin52989982020-03-05 17:40:49 +0800197
198 if (ll > 0 && prefix == nullptr) {
199 auto [s, l] = mAudioPowerUsage.dump(ll);
200 ss << s;
201 ll -= l;
202 }
Andy Hung06f3aba2019-12-03 16:36:42 -0800203 return { ss.str(), lines - ll };
204}
205
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800206void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
207{
208 auto actions = mActions.getActionsForItem(item); // internally locked.
209 // Execute actions with no lock held.
210 for (const auto& action : actions) {
211 (*action)(item);
212 }
213}
214
Andy Hungea186fa2020-01-09 18:13:15 -0800215// HELPER METHODS
216
217std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
218{
219 int32_t threadId_int32{};
220 if (mAnalyticsState->timeMachine().get(
221 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
222 return {};
223 }
224 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
225}
226
Andy Hungce9b6632020-04-28 20:15:17 -0700227// DeviceUse helper class.
228void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700229 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700230 const std::string& key = item->getKey();
231 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700232 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
233 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
234 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700235 - 1);
236 // deliver statistics
237 int64_t deviceTimeNs = 0;
238 mAudioAnalytics.mAnalyticsState->timeMachine().get(
239 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
240 std::string encoding;
241 mAudioAnalytics.mAnalyticsState->timeMachine().get(
242 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
243 int32_t frameCount = 0;
244 mAudioAnalytics.mAnalyticsState->timeMachine().get(
245 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hungea840382020-05-05 21:50:17 -0700246 std::string inputDevices;
247 mAudioAnalytics.mAnalyticsState->timeMachine().get(
248 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevices);
Andy Hungce9b6632020-04-28 20:15:17 -0700249 int32_t intervalCount = 0;
250 mAudioAnalytics.mAnalyticsState->timeMachine().get(
251 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
252 std::string outputDevices;
253 mAudioAnalytics.mAnalyticsState->timeMachine().get(
254 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
255 int32_t sampleRate = 0;
256 mAudioAnalytics.mAnalyticsState->timeMachine().get(
257 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700258 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700259 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700260 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
261 // We may have several devices.
262 // Strings allow us to mix input and output devices together.
263 // TODO: review if we want to separate them.
264 std::stringstream ss;
265 for (const auto& devicePairs : { outputDevices, inputDevices }) {
266 const auto devaddrvec = MediaMetricsService::getDeviceAddressPairs(devicePairs);
267 for (const auto& [device, addr] : devaddrvec) {
268 if (ss.tellp() > 0) ss << "|"; // delimit devices with '|'.
269 ss << device;
270 }
271 }
272 std::string devices = ss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700273
274 // Get connected device name if from bluetooth.
275 bool isBluetooth = false;
Andy Hungea840382020-05-05 21:50:17 -0700276 std::string deviceNames; // we only have one device name at this time.
Andy Hungce9b6632020-04-28 20:15:17 -0700277 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
278 isBluetooth = true;
279 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700280 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
281 // We don't check if deviceName is sanitized.
282 // TODO: remove reserved chars such as '|' and replace with a char like '_'.
Andy Hungce9b6632020-04-28 20:15:17 -0700283 }
284
Andy Hungea840382020-05-05 21:50:17 -0700285 switch (itemType) {
286 case RECORD: {
287 std::string callerName;
288 mAudioAnalytics.mAnalyticsState->timeMachine().get(
289 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
Andy Hungce9b6632020-04-28 20:15:17 -0700290
Andy Hungea840382020-05-05 21:50:17 -0700291 std::string packageName;
292 int64_t versionCode = 0;
293 int32_t uid = -1;
294 mAudioAnalytics.mAnalyticsState->timeMachine().get(
295 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
296 if (uid != -1) {
297 std::tie(packageName, versionCode) =
298 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
299 }
300
301 int32_t selectedDeviceId = 0;
302 mAudioAnalytics.mAnalyticsState->timeMachine().get(
303 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
304 std::string source;
305 mAudioAnalytics.mAnalyticsState->timeMachine().get(
306 key, AMEDIAMETRICS_PROP_SOURCE, &source);
307
308 ALOGD("(key=%s) id:%s endAudioIntervalGroup devices:%s deviceNames:%s "
309 "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
310 "sampleRate:%d "
311 "packageName:%s "
312 "selectedDeviceId:%d "
313 "callerName:%s source:%s",
314 key.c_str(), id.c_str(), devices.c_str(), deviceNames.c_str(),
315 (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
316 sampleRate,
317 packageName.c_str(), selectedDeviceId,
318 callerName.c_str(), source.c_str());
319
320#ifdef STATSD
321 if (mAudioAnalytics.mDeliverStatistics) {
322 (void)android::util::stats_write(
323 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED
324 /* timestamp, */
325 /* mediaApexVersion, */
326 , devices.c_str()
327 , deviceNames.c_str()
328 , deviceTimeNs
329 , encoding.c_str()
330 , frameCount
331 , intervalCount
332 , sampleRate
333 , flags.c_str()
334
335 , packageName.c_str()
336 , selectedDeviceId
337 , callerName.c_str()
338 , source.c_str()
339 );
340 }
341#endif
342 } break;
343 case THREAD: {
344 std::string type;
345 mAudioAnalytics.mAnalyticsState->timeMachine().get(
346 key, AMEDIAMETRICS_PROP_TYPE, &type);
347 int32_t underrun = 0; // zero for record types
348 mAudioAnalytics.mAnalyticsState->timeMachine().get(
349 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
350 ALOGD("(key=%s) id:%s endAudioIntervalGroup devices:%s deviceNames:%s "
351 "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
352 "sampleRate:%d underrun:%d "
353 "flags:%s type:%s",
354 key.c_str(), id.c_str(), devices.c_str(), deviceNames.c_str(),
355 (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
356 sampleRate, underrun,
357 flags.c_str(), type.c_str());
358#ifdef STATSD
359 if (mAudioAnalytics.mDeliverStatistics) {
360 (void)android::util::stats_write(
361 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED
362 /* timestamp, */
363 /* mediaApexVersion, */
364 , devices.c_str()
365 , deviceNames.c_str()
366 , deviceTimeNs
367 , encoding.c_str()
368 , frameCount
369 , intervalCount
370 , sampleRate
371 , flags.c_str()
372
373 , underrun
374 , type.c_str()
375 );
376 }
377#endif
378 } break;
379 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700380 std::string callerName;
381 mAudioAnalytics.mAnalyticsState->timeMachine().get(
382 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
383 std::string contentType;
384 mAudioAnalytics.mAnalyticsState->timeMachine().get(
385 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
386 double deviceLatencyMs = 0.;
387 mAudioAnalytics.mAnalyticsState->timeMachine().get(
388 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
389 double deviceStartupMs = 0.;
390 mAudioAnalytics.mAnalyticsState->timeMachine().get(
391 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
392 double deviceVolume = 0.;
393 mAudioAnalytics.mAnalyticsState->timeMachine().get(
394 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
395 std::string packageName;
396 int64_t versionCode = 0;
397 int32_t uid = -1;
398 mAudioAnalytics.mAnalyticsState->timeMachine().get(
399 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
400 if (uid != -1) {
401 std::tie(packageName, versionCode) =
402 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
403 }
404 double playbackPitch = 0.;
405 mAudioAnalytics.mAnalyticsState->timeMachine().get(
406 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
407 double playbackSpeed = 0.;
408 mAudioAnalytics.mAnalyticsState->timeMachine().get(
409 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
410 int32_t selectedDeviceId = 0;
411 mAudioAnalytics.mAnalyticsState->timeMachine().get(
412 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700413 std::string streamType;
414 mAudioAnalytics.mAnalyticsState->timeMachine().get(
415 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
416 int32_t underrun = 0;
417 mAudioAnalytics.mAnalyticsState->timeMachine().get(
418 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700419 std::string usage;
420 mAudioAnalytics.mAnalyticsState->timeMachine().get(
421 key, AMEDIAMETRICS_PROP_USAGE, &usage);
422
Andy Hungea840382020-05-05 21:50:17 -0700423 ALOGD("(key=%s) id:%s endAudioIntervalGroup devices:%s deviceNames:%s "
Andy Hungce9b6632020-04-28 20:15:17 -0700424 "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
425 "sampleRate:%d underrun:%d "
426 "callerName:%s contentType:%s "
Andy Hungea840382020-05-05 21:50:17 -0700427 "deviceLatencyMs:%lf deviceStartupMs:%lf deviceVolume:%lf "
Andy Hungce9b6632020-04-28 20:15:17 -0700428 "packageName:%s playbackPitch:%lf playbackSpeed:%lf "
Andy Hungea840382020-05-05 21:50:17 -0700429 "selectedDeviceId:%d streamType:%s usage:%s",
430 key.c_str(), id.c_str(), devices.c_str(), deviceNames.c_str(),
Andy Hungce9b6632020-04-28 20:15:17 -0700431 (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
432 sampleRate, underrun,
433 callerName.c_str(), contentType.c_str(),
434 deviceLatencyMs, deviceStartupMs, deviceVolume,
435 packageName.c_str(), playbackPitch, playbackSpeed,
Andy Hungea840382020-05-05 21:50:17 -0700436 selectedDeviceId, streamType.c_str(), usage.c_str());
Andy Hungce9b6632020-04-28 20:15:17 -0700437#ifdef STATSD
438 if (mAudioAnalytics.mDeliverStatistics) {
439 (void)android::util::stats_write(
440 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED
441 /* timestamp, */
442 /* mediaApexVersion, */
Andy Hungea840382020-05-05 21:50:17 -0700443 , devices.c_str()
444 , deviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700445 , deviceTimeNs
446 , encoding.c_str()
447 , frameCount
448 , intervalCount
449 , sampleRate
Andy Hungea840382020-05-05 21:50:17 -0700450 , flags.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700451 , underrun
452
453 , packageName.c_str()
454 , (float)deviceLatencyMs
455 , (float)deviceStartupMs
456 , (float)deviceVolume
457 , selectedDeviceId
Andy Hungea840382020-05-05 21:50:17 -0700458 , streamType.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700459 , usage.c_str()
460 , contentType.c_str()
461 , callerName.c_str()
462 );
463 }
464#endif
Andy Hungea840382020-05-05 21:50:17 -0700465 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700466 }
467
468 // Report this as needed.
469 if (isBluetooth) {
470 // report this for Bluetooth
471 }
472}
473
474// DeviceConnection helper class.
475void AudioAnalytics::DeviceConnection::a2dpConnected(
476 const std::shared_ptr<const android::mediametrics::Item> &item) {
477 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700478 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700479 {
480 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700481 mA2dpConnectionServiceNs = atNs;
482 ++mA2dpConnectionServices;
483
484 if (mA2dpConnectionRequestNs == 0) {
485 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
486 }
487 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700488 }
489 std::string name;
490 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700491 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
492 key.c_str(), name.c_str(), (long long)atNs);
493
Andy Hungce9b6632020-04-28 20:15:17 -0700494}
495
496void AudioAnalytics::DeviceConnection::createPatch(
497 const std::shared_ptr<const android::mediametrics::Item> &item) {
498 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700499 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700500 const std::string& key = item->getKey();
501 std::string outputDevices;
502 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700503 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700504 // TODO compare address
Andy Hungea840382020-05-05 21:50:17 -0700505 int64_t timeDiff = item->getTimestamp();
506 if (mA2dpConnectionRequestNs == 0) {
507 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
508 timeDiff -= mA2dpConnectionServiceNs;
509 } else {
510 timeDiff -= mA2dpConnectionRequestNs;
511 }
Andy Hungce9b6632020-04-28 20:15:17 -0700512 ALOGD("(key=%s) A2DP device connection time: %lld", key.c_str(), (long long)timeDiff);
Andy Hungea840382020-05-05 21:50:17 -0700513 mA2dpConnectionRequestNs = 0;
514 mA2dpConnectionServiceNs = 0;
515 ++mA2dpConnectionSuccesses;
516
517#ifdef STATSD
518 if (mAudioAnalytics.mDeliverStatistics) {
519 (void)android::util::stats_write(
520 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
521 /* timestamp, */
522 /* mediaApexVersion, */
523 , "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"
524 , android::util::MEDIAMETRICS_AUDIO_DEVICE_CONNECTION_REPORTED__RESULT__SUCCESS
525 , /* connection_time_ms */ timeDiff * 1e-6 /* NS to MS */
526 , /* connection_count */ 1
527 );
528 }
529#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700530 }
531}
532
Andy Hungea840382020-05-05 21:50:17 -0700533// Called through AudioManager when the BT service wants to enable
534void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
535 const std::shared_ptr<const android::mediametrics::Item> &item) {
536 const int64_t atNs = item->getTimestamp();
537 const std::string& key = item->getKey();
538 std::string state;
539 item->get(AMEDIAMETRICS_PROP_STATE, &state);
540 if (state != "connected") return;
541 {
542 std::lock_guard l(mLock);
543 mA2dpConnectionRequestNs = atNs;
544 ++mA2dpConnectionRequests;
545 }
546 ALOGD("(key=%s) a2dp connection request atNs:%lld",
547 key.c_str(), (long long)atNs);
548 // TODO: attempt to cancel a timed event, rather than let it expire.
549 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
550}
551
Andy Hungce9b6632020-04-28 20:15:17 -0700552void AudioAnalytics::DeviceConnection::expire() {
553 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700554 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
555 if (mA2dpConnectionServiceNs == 0) {
556 ALOGD("A2DP device connection service cancels");
557 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700558
Andy Hungea840382020-05-05 21:50:17 -0700559#ifdef STATSD
560 if (mAudioAnalytics.mDeliverStatistics) {
561 (void)android::util::stats_write(
562 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
563 /* timestamp, */
564 /* mediaApexVersion, */
565 , "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"
566 , android::util::MEDIAMETRICS_AUDIO_DEVICE_CONNECTION_REPORTED__RESULT__JAVA_SERVICE_CANCEL
567 , /* connection_time_ms */ 0.f
568 , /* connection_count */ 1
569 );
570 }
571#endif
572 return;
573 }
574
575 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
576 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700577 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700578 ALOGD("A2DP device connection expired, state unknown");
579 mA2dpConnectionRequestNs = 0;
580 mA2dpConnectionServiceNs = 0;
581 ++mA2dpConnectionUnknowns; // connection result unknown
582#ifdef STATSD
583 if (mAudioAnalytics.mDeliverStatistics) {
584 (void)android::util::stats_write(
585 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
586 /* timestamp, */
587 /* mediaApexVersion, */
588 , "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"
589 , android::util::MEDIAMETRICS_AUDIO_DEVICE_CONNECTION_REPORTED__RESULT__UNKNOWN
590 , /* connection_time_ms */ 0.f
591 , /* connection_count */ 1
592 );
593 }
594#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700595}
596
Andy Hung06f3aba2019-12-03 16:36:42 -0800597} // namespace android