blob: ff864536e9af359dabb4499ef0323b692a209202 [file] [log] [blame]
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08001/*
2 * Copyright (C) 2016 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
17package com.android.server.audio;
18
19import android.annotation.NonNull;
Eric Laurente5a351c2017-09-27 20:11:51 -070020import android.content.Context;
21import android.content.pm.PackageManager;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080022import android.media.AudioAttributes;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080023import android.media.AudioManager;
24import android.media.AudioPlaybackConfiguration;
25import android.media.AudioSystem;
26import android.media.IPlaybackConfigDispatcher;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080027import android.media.PlayerBase;
Jean-Michel Trividce82ab2017-02-07 16:02:33 -080028import android.media.VolumeShaper;
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -080029import android.os.Binder;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080030import android.os.IBinder;
31import android.os.RemoteException;
32import android.util.Log;
33
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -070034import com.android.internal.util.ArrayUtils;
35
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080036import java.io.PrintWriter;
37import java.text.DateFormat;
38import java.util.ArrayList;
Jean-Michel Trivi56266192017-07-18 14:53:40 -070039import java.util.Collections;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080040import java.util.Date;
41import java.util.HashMap;
42import java.util.Iterator;
43import java.util.List;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080044import java.util.Set;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080045
46/**
47 * Class to receive and dispatch updates from AudioSystem about recording configurations.
48 */
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -080049public final class PlaybackActivityMonitor
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080050 implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080051
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070052 public static final String TAG = "AudioService.PlaybackActivityMonitor";
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -080053
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070054 private static final boolean DEBUG = false;
55 private static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080056
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070057 private static final VolumeShaper.Configuration DUCK_VSHAPE =
Andy Hung7da0e982017-02-22 12:34:21 -080058 new VolumeShaper.Configuration.Builder()
59 .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
60 .setCurve(new float[] { 0.f, 1.f } /* times */,
61 new float[] { 1.f, 0.2f } /* volumes */)
62 .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
Jean-Michel Trivi4c86efa12017-04-20 18:13:34 -070063 .setDuration(MediaFocusControl.getFocusRampTimeMs(
Andy Hung7da0e982017-02-22 12:34:21 -080064 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
65 new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
66 .build()))
67 .build();
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070068 private static final VolumeShaper.Configuration DUCK_ID =
Andy Hung7da0e982017-02-22 12:34:21 -080069 new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070070 private static final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
Andy Hung7da0e982017-02-22 12:34:21 -080071 new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
72 .createIfNeeded()
73 .build();
Andy Hung7da0e982017-02-22 12:34:21 -080074
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -070075 // TODO support VolumeShaper on those players
76 private static final int[] UNDUCKABLE_PLAYER_TYPES = {
77 AudioPlaybackConfiguration.PLAYER_TYPE_AAUDIO,
78 AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL,
79 };
80
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -070081 // like a PLAY_CREATE_IF_NEEDED operation but with a skip to the end of the ramp
82 private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
83 new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
84
Andy Hung7da0e982017-02-22 12:34:21 -080085 private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080086 // a public client is one that needs an anonymized version of the playback configurations, we
87 // keep track of whether there is at least one to know when we need to create the list of
88 // playback configurations that do not contain uid/pid/package name information.
89 private boolean mHasPublicClients = false;
90
91 private final Object mPlayerLock = new Object();
Andy Hung7da0e982017-02-22 12:34:21 -080092 private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080093 new HashMap<Integer, AudioPlaybackConfiguration>();
94
Eric Laurente5a351c2017-09-27 20:11:51 -070095 private final Context mContext;
96 private int mSavedAlarmVolume = -1;
97 private final int mMaxAlarmVolume;
98 private int mPrivilegedAlarmActiveCount = 0;
99
100 PlaybackActivityMonitor(Context context, int maxAlarmVolume) {
101 mContext = context;
102 mMaxAlarmVolume = maxAlarmVolume;
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800103 PlayMonitorClient.sListenerDeathMonitor = this;
104 AudioPlaybackConfiguration.sPlayerDeathMonitor = this;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800105 }
106
107 //=================================================================
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700108 private final ArrayList<Integer> mBannedUids = new ArrayList<Integer>();
109
110 // see AudioManagerInternal.disableAudioForUid(boolean disable, int uid)
111 public void disableAudioForUid(boolean disable, int uid) {
112 synchronized(mPlayerLock) {
113 final int index = mBannedUids.indexOf(new Integer(uid));
114 if (index >= 0) {
115 if (!disable) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700116 if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700117 sEventLogger.log(new AudioEventLogger.StringEvent("unbanning uid:" + uid));
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700118 }
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700119 mBannedUids.remove(index);
120 // nothing else to do, future playback requests from this uid are ok
121 } // no else to handle, uid already present, so disabling again is no-op
122 } else {
123 if (disable) {
124 for (AudioPlaybackConfiguration apc : mPlayers.values()) {
125 checkBanPlayer(apc, uid);
126 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700127 if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700128 sEventLogger.log(new AudioEventLogger.StringEvent("banning uid:" + uid));
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700129 }
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700130 mBannedUids.add(new Integer(uid));
131 } // no else to handle, uid already not in list, so enabling again is no-op
132 }
133 }
134 }
135
136 private boolean checkBanPlayer(@NonNull AudioPlaybackConfiguration apc, int uid) {
137 final boolean toBan = (apc.getClientUid() == uid);
138 if (toBan) {
139 final int piid = apc.getPlayerInterfaceId();
140 try {
141 Log.v(TAG, "banning player " + piid + " uid:" + uid);
142 apc.getPlayerProxy().pause();
143 } catch (Exception e) {
144 Log.e(TAG, "error banning player " + piid + " uid:" + uid, e);
145 }
146 }
147 return toBan;
148 }
149
150 //=================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800151 // Track players and their states
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800152 // methods playerAttributes, playerEvent, releasePlayer are all oneway calls
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800153 // into AudioService. They trigger synchronous dispatchPlaybackChange() which updates
154 // all listeners as oneway calls.
155
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800156 public int trackPlayer(PlayerBase.PlayerIdCard pic) {
157 final int newPiid = AudioSystem.newAudioPlayerId();
158 if (DEBUG) { Log.v(TAG, "trackPlayer() new piid=" + newPiid); }
159 final AudioPlaybackConfiguration apc =
160 new AudioPlaybackConfiguration(pic, newPiid,
161 Binder.getCallingUid(), Binder.getCallingPid());
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800162 apc.init();
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700163 sEventLogger.log(new NewPlayerEvent(apc));
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800164 synchronized(mPlayerLock) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800165 mPlayers.put(newPiid, apc);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800166 }
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800167 return newPiid;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800168 }
169
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800170 public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800171 final boolean change;
172 synchronized(mPlayerLock) {
173 final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800174 if (checkConfigurationCaller(piid, apc, binderUid)) {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700175 sEventLogger.log(new AudioAttrEvent(piid, attr));
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800176 change = apc.handleAudioAttributesEvent(attr);
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800177 } else {
178 Log.e(TAG, "Error updating audio attributes");
179 change = false;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800180 }
181 }
182 if (change) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700183 dispatchPlaybackChange(false);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800184 }
185 }
186
Jean-Michel Trivid51d3982017-10-10 16:32:38 -0700187 private static final int FLAGS_FOR_SILENCE_OVERRIDE =
188 AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
189 AudioAttributes.FLAG_BYPASS_MUTE;
190
Eric Laurente5a351c2017-09-27 20:11:51 -0700191 private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) {
192 if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED ||
193 apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
Jean-Michel Trivid51d3982017-10-10 16:32:38 -0700194 if ((apc.getAudioAttributes().getAllFlags() & FLAGS_FOR_SILENCE_OVERRIDE)
195 == FLAGS_FOR_SILENCE_OVERRIDE &&
Eric Laurente5a351c2017-09-27 20:11:51 -0700196 apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM &&
197 mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
198 apc.getClientPid(), apc.getClientUid()) ==
199 PackageManager.PERMISSION_GRANTED) {
200 if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
201 apc.getPlayerState() != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
202 if (mPrivilegedAlarmActiveCount++ == 0) {
203 mSavedAlarmVolume = AudioSystem.getStreamVolumeIndex(
204 AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER);
205 AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
206 mMaxAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
207 }
208 } else if (event != AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
209 apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
210 if (--mPrivilegedAlarmActiveCount == 0) {
211 if (AudioSystem.getStreamVolumeIndex(
212 AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER) ==
213 mMaxAlarmVolume) {
214 AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
215 mSavedAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
216 }
217 }
218 }
219 }
220 }
221 }
222
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800223 public void playerEvent(int piid, int event, int binderUid) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800224 if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800225 final boolean change;
226 synchronized(mPlayerLock) {
227 final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700228 if (apc == null) {
229 return;
230 }
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700231 sEventLogger.log(new PlayerEvent(piid, event));
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700232 if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
233 for (Integer uidInteger: mBannedUids) {
234 if (checkBanPlayer(apc, uidInteger.intValue())) {
235 // player was banned, do not update its state
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700236 sEventLogger.log(new AudioEventLogger.StringEvent(
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700237 "not starting piid:" + piid + " ,is banned"));
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700238 return;
239 }
240 }
241 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700242 if (apc.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
243 // FIXME SoundPool not ready for state reporting
Jean-Michel Trivif1d82762017-02-14 14:24:37 -0800244 return;
245 }
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800246 if (checkConfigurationCaller(piid, apc, binderUid)) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800247 //TODO add generation counter to only update to the latest state
Eric Laurente5a351c2017-09-27 20:11:51 -0700248 checkVolumeForPrivilegedAlarm(apc, event);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800249 change = apc.handleStateEvent(event);
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800250 } else {
251 Log.e(TAG, "Error handling event " + event);
252 change = false;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800253 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700254 if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
255 mDuckingManager.checkDuck(apc);
Jean-Michel Trivicafed632017-04-03 18:49:45 -0700256 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800257 }
258 if (change) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700259 dispatchPlaybackChange(event == AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800260 }
261 }
262
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -0700263 public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio, int binderUid) {
264 // no check on UID yet because this is only for logging at the moment
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700265 sEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid));
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -0700266 }
267
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800268 public void releasePlayer(int piid, int binderUid) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800269 if (DEBUG) { Log.v(TAG, "releasePlayer() for piid=" + piid); }
270 synchronized(mPlayerLock) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800271 final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
272 if (checkConfigurationCaller(piid, apc, binderUid)) {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700273 sEventLogger.log(new AudioEventLogger.StringEvent(
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700274 "releasing player piid:" + piid));
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800275 mPlayers.remove(new Integer(piid));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700276 mDuckingManager.removeReleased(apc);
Eric Laurente5a351c2017-09-27 20:11:51 -0700277 checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
Jean-Michel Trivic2e7ceb2017-09-05 12:13:05 -0700278 apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800279 }
280 }
281 }
282
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800283 // Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor
284 @Override
285 public void playerDeath(int piid) {
286 releasePlayer(piid, 0);
287 }
288
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800289 protected void dump(PrintWriter pw) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800290 // players
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800291 pw.println("\nPlaybackActivityMonitor dump time: "
292 + DateFormat.getTimeInstance().format(new Date()));
293 synchronized(mPlayerLock) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700294 pw.println("\n playback listeners:");
295 synchronized(mClients) {
296 for (PlayMonitorClient pmc : mClients) {
297 pw.print(" " + (pmc.mIsPrivileged ? "(S)" : "(P)")
298 + pmc.toString());
299 }
300 }
301 pw.println("\n");
Jean-Michel Trivi56266192017-07-18 14:53:40 -0700302 // all players
303 pw.println("\n players:");
304 final List<Integer> piidIntList = new ArrayList<Integer>(mPlayers.keySet());
305 Collections.sort(piidIntList);
306 for (Integer piidInt : piidIntList) {
307 final AudioPlaybackConfiguration apc = mPlayers.get(piidInt);
308 if (apc != null) {
309 apc.dump(pw);
310 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800311 }
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800312 // ducked players
Jean-Michel Trivi56266192017-07-18 14:53:40 -0700313 pw.println("\n ducked players piids:");
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700314 mDuckingManager.dump(pw);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800315 // players muted due to the device ringing or being in a call
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700316 pw.print("\n muted player piids:");
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800317 for (int piid : mMutedPlayers) {
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700318 pw.print(" " + piid);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800319 }
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700320 pw.println();
321 // banned players:
322 pw.print("\n banned uids:");
323 for (int uid : mBannedUids) {
324 pw.print(" " + uid);
325 }
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700326 pw.println("\n");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700327 // log
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700328 sEventLogger.dump(pw);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800329 }
330 }
331
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800332 /**
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -0700333 * Check that piid and uid are valid for the given valid configuration.
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800334 * @param piid the piid of the player.
335 * @param apc the configuration found for this piid.
336 * @param binderUid actual uid of client trying to signal a player state/event/attributes.
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -0700337 * @return true if the call is valid and the change should proceed, false otherwise. Always
338 * returns false when apc is null.
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800339 */
340 private static boolean checkConfigurationCaller(int piid,
341 final AudioPlaybackConfiguration apc, int binderUid) {
342 if (apc == null) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800343 return false;
344 } else if ((binderUid != 0) && (apc.getClientUid() != binderUid)) {
345 Log.e(TAG, "Forbidden operation from uid " + binderUid + " for player " + piid);
346 return false;
347 }
348 return true;
349 }
350
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700351 /**
352 * Sends new list after update of playback configurations
353 * @param iplayerReleased indicates if the change was due to a player being released
354 */
355 private void dispatchPlaybackChange(boolean iplayerReleased) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800356 synchronized (mClients) {
357 // typical use case, nobody is listening, don't do any work
358 if (mClients.isEmpty()) {
359 return;
360 }
361 }
362 if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); }
363 final List<AudioPlaybackConfiguration> configsSystem;
364 // list of playback configurations for "public consumption". It is only computed if there
365 // are non-system playback activity listeners.
366 final List<AudioPlaybackConfiguration> configsPublic;
367 synchronized (mPlayerLock) {
368 if (mPlayers.isEmpty()) {
369 return;
370 }
371 configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
372 }
373 synchronized (mClients) {
374 // was done at beginning of method, but could have changed
375 if (mClients.isEmpty()) {
376 return;
377 }
378 configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null;
379 final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
380 while (clientIterator.hasNext()) {
381 final PlayMonitorClient pmc = clientIterator.next();
382 try {
383 // do not spam the logs if there are problems communicating with this client
384 if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) {
385 if (pmc.mIsPrivileged) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700386 pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem,
387 iplayerReleased);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800388 } else {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700389 // non-system clients don't have the control interface IPlayer, so
390 // they don't need to flush commands when a player was released
391 pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800392 }
393 }
394 } catch (RemoteException e) {
395 pmc.mErrorCount++;
396 Log.e(TAG, "Error (" + pmc.mErrorCount +
397 ") trying to dispatch playback config change to " + pmc, e);
398 }
399 }
400 }
401 }
402
403 private ArrayList<AudioPlaybackConfiguration> anonymizeForPublicConsumption(
404 List<AudioPlaybackConfiguration> sysConfigs) {
405 ArrayList<AudioPlaybackConfiguration> publicConfigs =
406 new ArrayList<AudioPlaybackConfiguration>();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800407 // only add active anonymized configurations,
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800408 for (AudioPlaybackConfiguration config : sysConfigs) {
409 if (config.isActive()) {
410 publicConfigs.add(AudioPlaybackConfiguration.anonymizedCopy(config));
411 }
412 }
413 return publicConfigs;
414 }
415
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800416
417 //=================================================================
418 // PlayerFocusEnforcer implementation
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800419 private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700420
421 private final DuckingManager mDuckingManager = new DuckingManager();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800422
423 @Override
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800424 public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800425 if (DEBUG) {
426 Log.v(TAG, String.format("duckPlayers: uids winner=%d loser=%d",
Jean-Michel Trivicafed632017-04-03 18:49:45 -0700427 winner.getClientUid(), loser.getClientUid()));
428 }
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800429 synchronized (mPlayerLock) {
430 if (mPlayers.isEmpty()) {
431 return true;
432 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700433 // check if this UID needs to be ducked (return false if not), and gather list of
434 // eligible players to duck
435 final Iterator<AudioPlaybackConfiguration> apcIterator = mPlayers.values().iterator();
436 final ArrayList<AudioPlaybackConfiguration> apcsToDuck =
437 new ArrayList<AudioPlaybackConfiguration>();
438 while (apcIterator.hasNext()) {
439 final AudioPlaybackConfiguration apc = apcIterator.next();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800440 if (!winner.hasSameUid(apc.getClientUid())
441 && loser.hasSameUid(apc.getClientUid())
442 && apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED)
443 {
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800444 if (!forceDuck && (apc.getAudioAttributes().getContentType() ==
445 AudioAttributes.CONTENT_TYPE_SPEECH)) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800446 // the player is speaking, ducking will make the speech unintelligible
447 // so let the app handle it instead
Jean-Michel Trivi087b6722017-05-10 13:05:06 -0700448 Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
449 + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
450 + " - SPEECH");
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800451 return false;
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -0700452 } else if (ArrayUtils.contains(UNDUCKABLE_PLAYER_TYPES, apc.getPlayerType())) {
Jean-Michel Trivi087b6722017-05-10 13:05:06 -0700453 Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
454 + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -0700455 + " due to type:"
456 + AudioPlaybackConfiguration.toLogFriendlyPlayerType(
457 apc.getPlayerType()));
Jean-Michel Trividce82ab2017-02-07 16:02:33 -0800458 return false;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800459 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700460 apcsToDuck.add(apc);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800461 }
462 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700463 // add the players eligible for ducking to the list, and duck them
464 // (if apcsToDuck is empty, this will at least mark this uid as ducked, so when
465 // players of the same uid start, they will be ducked by DuckingManager.checkDuck())
466 mDuckingManager.duckUid(loser.getClientUid(), apcsToDuck);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800467 }
468 return true;
469 }
470
471 @Override
472 public void unduckPlayers(FocusRequester winner) {
473 if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
474 synchronized (mPlayerLock) {
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700475 mDuckingManager.unduckUid(winner.getClientUid(), mPlayers);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800476 }
477 }
478
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800479 @Override
480 public void mutePlayersForCall(int[] usagesToMute) {
481 if (DEBUG) {
482 String log = new String("mutePlayersForCall: usages=");
483 for (int usage : usagesToMute) { log += " " + usage; }
484 Log.v(TAG, log);
485 }
486 synchronized (mPlayerLock) {
487 final Set<Integer> piidSet = mPlayers.keySet();
488 final Iterator<Integer> piidIterator = piidSet.iterator();
489 // find which players to mute
490 while (piidIterator.hasNext()) {
491 final Integer piid = piidIterator.next();
492 final AudioPlaybackConfiguration apc = mPlayers.get(piid);
Jean-Michel Trivibd39cfa2017-02-17 17:23:36 -0800493 if (apc == null) {
494 continue;
495 }
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800496 final int playerUsage = apc.getAudioAttributes().getUsage();
497 boolean mute = false;
498 for (int usageToMute : usagesToMute) {
499 if (playerUsage == usageToMute) {
500 mute = true;
501 break;
502 }
503 }
504 if (mute) {
505 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700506 sEventLogger.log((new AudioEventLogger.StringEvent("call: muting piid:"
507 + piid + " uid:" + apc.getClientUid())).printLog(TAG));
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800508 apc.getPlayerProxy().setVolume(0.0f);
Jean-Michel Trivicafed632017-04-03 18:49:45 -0700509 mMutedPlayers.add(new Integer(piid));
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800510 } catch (Exception e) {
Jean-Michel Trivi952f2342017-03-06 16:16:56 -0800511 Log.e(TAG, "call: error muting player " + piid, e);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800512 }
513 }
514 }
515 }
516 }
517
518 @Override
519 public void unmutePlayersForCall() {
520 if (DEBUG) {
521 Log.v(TAG, "unmutePlayersForCall()");
522 }
523 synchronized (mPlayerLock) {
524 if (mMutedPlayers.isEmpty()) {
525 return;
526 }
527 for (int piid : mMutedPlayers) {
528 final AudioPlaybackConfiguration apc = mPlayers.get(piid);
529 if (apc != null) {
530 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700531 sEventLogger.log(new AudioEventLogger.StringEvent("call: unmuting piid:"
532 + piid).printLog(TAG));
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800533 apc.getPlayerProxy().setVolume(1.0f);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800534 } catch (Exception e) {
Jean-Michel Trivi087b6722017-05-10 13:05:06 -0700535 Log.e(TAG, "call: error unmuting player " + piid + " uid:"
536 + apc.getClientUid(), e);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800537 }
538 }
539 }
Jean-Michel Trivi579c5112017-02-10 09:47:30 -0800540 mMutedPlayers.clear();
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800541 }
542 }
543
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800544 //=================================================================
545 // Track playback activity listeners
546
547 void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
548 if (pcdb == null) {
549 return;
550 }
551 synchronized(mClients) {
552 final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
553 if (pmc.init()) {
554 if (!isPrivileged) {
555 mHasPublicClients = true;
556 }
557 mClients.add(pmc);
558 }
559 }
560 }
561
562 void unregisterPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
563 if (pcdb == null) {
564 return;
565 }
566 synchronized(mClients) {
567 final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
568 boolean hasPublicClients = false;
569 // iterate over the clients to remove the dispatcher to remove, and reevaluate at
570 // the same time if we still have a public client.
571 while (clientIterator.hasNext()) {
572 PlayMonitorClient pmc = clientIterator.next();
573 if (pcdb.equals(pmc.mDispatcherCb)) {
574 pmc.release();
575 clientIterator.remove();
576 } else {
577 if (!pmc.mIsPrivileged) {
578 hasPublicClients = true;
579 }
580 }
581 }
582 mHasPublicClients = hasPublicClients;
583 }
584 }
585
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800586 List<AudioPlaybackConfiguration> getActivePlaybackConfigurations(boolean isPrivileged) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800587 synchronized(mPlayers) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800588 if (isPrivileged) {
589 return new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
590 } else {
591 final List<AudioPlaybackConfiguration> configsPublic;
592 synchronized (mPlayerLock) {
593 configsPublic = anonymizeForPublicConsumption(
594 new ArrayList<AudioPlaybackConfiguration>(mPlayers.values()));
595 }
596 return configsPublic;
597 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800598 }
599 }
600
601
602 /**
603 * Inner class to track clients that want to be notified of playback updates
604 */
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -0700605 private static final class PlayMonitorClient implements IBinder.DeathRecipient {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800606
607 // can afford to be static because only one PlaybackActivityMonitor ever instantiated
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800608 static PlaybackActivityMonitor sListenerDeathMonitor;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800609
610 final IPlaybackConfigDispatcher mDispatcherCb;
611 final boolean mIsPrivileged;
612
613 int mErrorCount = 0;
614 // number of errors after which we don't update this client anymore to not spam the logs
615 static final int MAX_ERRORS = 5;
616
617 PlayMonitorClient(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
618 mDispatcherCb = pcdb;
619 mIsPrivileged = isPrivileged;
620 }
621
622 public void binderDied() {
623 Log.w(TAG, "client died");
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800624 sListenerDeathMonitor.unregisterPlaybackCallback(mDispatcherCb);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800625 }
626
627 boolean init() {
628 try {
629 mDispatcherCb.asBinder().linkToDeath(this, 0);
630 return true;
631 } catch (RemoteException e) {
632 Log.w(TAG, "Could not link to client death", e);
633 return false;
634 }
635 }
636
637 void release() {
638 mDispatcherCb.asBinder().unlinkToDeath(this, 0);
639 }
640 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700641
642 //=================================================================
643 // Class to handle ducking related operations for a given UID
644 private static final class DuckingManager {
645 private final HashMap<Integer, DuckedApp> mDuckers = new HashMap<Integer, DuckedApp>();
646
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700647 synchronized void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
648 if (DEBUG) { Log.v(TAG, "DuckingManager: duckUid() uid:"+ uid); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700649 if (!mDuckers.containsKey(uid)) {
650 mDuckers.put(uid, new DuckedApp(uid));
651 }
652 final DuckedApp da = mDuckers.get(uid);
653 for (AudioPlaybackConfiguration apc : apcsToDuck) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700654 da.addDuck(apc, false /*skipRamp*/);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700655 }
656 }
657
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700658 synchronized void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
659 if (DEBUG) { Log.v(TAG, "DuckingManager: unduckUid() uid:"+ uid); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700660 final DuckedApp da = mDuckers.remove(uid);
661 if (da == null) {
662 return;
663 }
664 da.removeUnduckAll(players);
665 }
666
667 // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700668 synchronized void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
669 if (DEBUG) { Log.v(TAG, "DuckingManager: checkDuck() player piid:"
670 + apc.getPlayerInterfaceId()+ " uid:"+ apc.getClientUid()); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700671 final DuckedApp da = mDuckers.get(apc.getClientUid());
672 if (da == null) {
673 return;
674 }
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700675 da.addDuck(apc, true /*skipRamp*/);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700676 }
677
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700678 synchronized void dump(PrintWriter pw) {
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700679 for (DuckedApp da : mDuckers.values()) {
680 da.dump(pw);
681 }
682 }
683
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700684 synchronized void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
685 final int uid = apc.getClientUid();
686 if (DEBUG) { Log.v(TAG, "DuckingManager: removedReleased() player piid: "
687 + apc.getPlayerInterfaceId() + " uid:" + uid); }
688 final DuckedApp da = mDuckers.get(uid);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700689 if (da == null) {
690 return;
691 }
692 da.removeReleased(apc);
693 }
694
695 private static final class DuckedApp {
696 private final int mUid;
697 private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
698
699 DuckedApp(int uid) {
700 mUid = uid;
701 }
702
703 void dump(PrintWriter pw) {
704 pw.print("\t uid:" + mUid + " piids:");
705 for (int piid : mDuckedPlayers) {
706 pw.print(" " + piid);
707 }
708 pw.println("");
709 }
710
711 // pre-conditions:
712 // * apc != null
713 // * apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700714 void addDuck(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700715 final int piid = new Integer(apc.getPlayerInterfaceId());
716 if (mDuckedPlayers.contains(piid)) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700717 if (DEBUG) { Log.v(TAG, "player piid:" + piid + " already ducked"); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700718 return;
719 }
720 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700721 sEventLogger.log((new DuckEvent(apc, skipRamp)).printLog(TAG));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700722 apc.getPlayerProxy().applyVolumeShaper(
723 DUCK_VSHAPE,
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700724 skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700725 mDuckedPlayers.add(piid);
726 } catch (Exception e) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700727 Log.e(TAG, "Error ducking player piid:" + piid + " uid:" + mUid, e);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700728 }
729 }
730
731 void removeUnduckAll(HashMap<Integer, AudioPlaybackConfiguration> players) {
732 for (int piid : mDuckedPlayers) {
733 final AudioPlaybackConfiguration apc = players.get(piid);
734 if (apc != null) {
735 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700736 sEventLogger.log((new AudioEventLogger.StringEvent("unducking piid:"
737 + piid)).printLog(TAG));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700738 apc.getPlayerProxy().applyVolumeShaper(
739 DUCK_ID,
740 VolumeShaper.Operation.REVERSE);
741 } catch (Exception e) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700742 Log.e(TAG, "Error unducking player piid:" + piid + " uid:" + mUid, e);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700743 }
744 } else {
745 // this piid was in the list of ducked players, but wasn't found
746 if (DEBUG) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700747 Log.v(TAG, "Error unducking player piid:" + piid
748 + ", player not found for uid " + mUid);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700749 }
750 }
751 }
752 mDuckedPlayers.clear();
753 }
754
755 void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
756 mDuckedPlayers.remove(new Integer(apc.getPlayerInterfaceId()));
757 }
758 }
759 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700760
761 //=================================================================
762 // For logging
763 private final static class PlayerEvent extends AudioEventLogger.Event {
764 // only keeping the player interface ID as it uniquely identifies the player in the event
765 final int mPlayerIId;
766 final int mState;
767
768 PlayerEvent(int piid, int state) {
769 mPlayerIId = piid;
770 mState = state;
771 }
772
773 @Override
774 public String eventToString() {
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -0700775 return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
776 .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
777 }
778 }
779
780 private final static class PlayerOpPlayAudioEvent extends AudioEventLogger.Event {
781 // only keeping the player interface ID as it uniquely identifies the player in the event
782 final int mPlayerIId;
783 final boolean mHasOp;
784 final int mUid;
785
786 PlayerOpPlayAudioEvent(int piid, boolean hasOp, int uid) {
787 mPlayerIId = piid;
788 mHasOp = hasOp;
789 mUid = uid;
790 }
791
792 @Override
793 public String eventToString() {
794 return new StringBuilder("player piid:").append(mPlayerIId)
795 .append(" has OP_PLAY_AUDIO:").append(mHasOp)
796 .append(" in uid:").append(mUid).toString();
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700797 }
798 }
799
800 private final static class NewPlayerEvent extends AudioEventLogger.Event {
801 private final int mPlayerIId;
802 private final int mPlayerType;
803 private final int mClientUid;
804 private final int mClientPid;
805 private final AudioAttributes mPlayerAttr;
806
807 NewPlayerEvent(AudioPlaybackConfiguration apc) {
808 mPlayerIId = apc.getPlayerInterfaceId();
809 mPlayerType = apc.getPlayerType();
810 mClientUid = apc.getClientUid();
811 mClientPid = apc.getClientPid();
812 mPlayerAttr = apc.getAudioAttributes();
813 }
814
815 @Override
816 public String eventToString() {
817 return new String("new player piid:" + mPlayerIId + " uid/pid:" + mClientUid + "/"
818 + mClientPid + " type:"
819 + AudioPlaybackConfiguration.toLogFriendlyPlayerType(mPlayerType)
820 + " attr:" + mPlayerAttr);
821 }
822 }
823
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700824 private static final class DuckEvent extends AudioEventLogger.Event {
825 private final int mPlayerIId;
826 private final boolean mSkipRamp;
827 private final int mClientUid;
828 private final int mClientPid;
829
830 DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
831 mPlayerIId = apc.getPlayerInterfaceId();
832 mSkipRamp = skipRamp;
833 mClientUid = apc.getClientUid();
834 mClientPid = apc.getClientPid();
835 }
836
837 @Override
838 public String eventToString() {
839 return new StringBuilder("ducking player piid:").append(mPlayerIId)
840 .append(" uid/pid:").append(mClientUid).append("/").append(mClientPid)
841 .append(" skip ramp:").append(mSkipRamp).toString();
842 }
843 }
844
845 private static final class AudioAttrEvent extends AudioEventLogger.Event {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700846 private final int mPlayerIId;
847 private final AudioAttributes mPlayerAttr;
848
849 AudioAttrEvent(int piid, AudioAttributes attr) {
850 mPlayerIId = piid;
851 mPlayerAttr = attr;
852 }
853
854 @Override
855 public String eventToString() {
856 return new String("player piid:" + mPlayerIId + " new AudioAttributes:" + mPlayerAttr);
857 }
858 }
859
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700860 private static final AudioEventLogger sEventLogger = new AudioEventLogger(100,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700861 "playback activity as reported through PlayerBase");
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800862}