1 /* 2 * Copyright (C) 2017 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 package com.android.tv; 17 18 import android.app.Activity; 19 import android.content.Context; 20 import android.media.AudioManager; 21 import android.os.Build; 22 import com.android.tv.receiver.AudioCapabilitiesReceiver; 23 import com.android.tv.ui.TunableTvView; 24 import com.android.tv.ui.TunableTvViewPlayingApi; 25 26 /** A helper class to help {@link MainActivity} to handle audio-related stuffs. */ 27 class AudioManagerHelper implements AudioManager.OnAudioFocusChangeListener { 28 private static final float AUDIO_MAX_VOLUME = 1.0f; 29 private static final float AUDIO_MIN_VOLUME = 0.0f; 30 private static final float AUDIO_DUCKING_VOLUME = 0.3f; 31 32 private final Activity mActivity; 33 private final TunableTvViewPlayingApi mTvView; 34 private final AudioManager mAudioManager; 35 private final AudioCapabilitiesReceiver mAudioCapabilitiesReceiver; 36 37 private boolean mAc3PassthroughSupported; 38 private int mAudioFocusStatus = AudioManager.AUDIOFOCUS_LOSS; 39 40 AudioManagerHelper(Activity activity, TunableTvViewPlayingApi tvView) { 41 mActivity = activity; 42 mTvView = tvView; 43 mAudioManager = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE); 44 mAudioCapabilitiesReceiver = 45 new AudioCapabilitiesReceiver( 46 activity, 47 new AudioCapabilitiesReceiver.OnAc3PassthroughCapabilityChangeListener() { 48 @Override 49 public void onAc3PassthroughCapabilityChange(boolean capability) { 50 mAc3PassthroughSupported = capability; 51 } 52 }); 53 mAudioCapabilitiesReceiver.register(); 54 } 55 56 /** 57 * Sets suitable volume to {@link TunableTvView} according to the current audio focus. If the 58 * focus status is {@link AudioManager#AUDIOFOCUS_LOSS} and the activity is under PIP mode, this 59 * method will finish the activity. 60 */ 61 void setVolumeByAudioFocusStatus() { 62 if (mTvView.isPlaying()) { 63 switch (mAudioFocusStatus) { 64 case AudioManager.AUDIOFOCUS_GAIN: 65 if (mTvView.isTimeShiftAvailable()) { 66 mTvView.timeshiftPlay(); 67 } else { 68 mTvView.setStreamVolume(AUDIO_MAX_VOLUME); 69 } 70 break; 71 case AudioManager.AUDIOFOCUS_LOSS: 72 if (TvFeatures.PICTURE_IN_PICTURE.isEnabled(mActivity) 73 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N 74 && mActivity.isInPictureInPictureMode()) { 75 mActivity.finish(); 76 break; 77 } 78 // fall through 79 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 80 if (mTvView.isTimeShiftAvailable()) { 81 mTvView.timeshiftPause(); 82 } else { 83 mTvView.setStreamVolume(AUDIO_MIN_VOLUME); 84 } 85 break; 86 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 87 if (mTvView.isTimeShiftAvailable()) { 88 mTvView.timeshiftPause(); 89 } else { 90 mTvView.setStreamVolume(AUDIO_DUCKING_VOLUME); 91 } 92 break; 93 } 94 } 95 } 96 97 /** 98 * Tries to request audio focus from {@link AudioManager} and set volume according to the 99 * returned result. 100 */ 101 void requestAudioFocus() { 102 int result = 103 mAudioManager.requestAudioFocus( 104 this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); 105 mAudioFocusStatus = 106 (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) 107 ? AudioManager.AUDIOFOCUS_GAIN 108 : AudioManager.AUDIOFOCUS_LOSS; 109 setVolumeByAudioFocusStatus(); 110 } 111 112 /** Abandons audio focus. */ 113 void abandonAudioFocus() { 114 mAudioFocusStatus = AudioManager.AUDIOFOCUS_LOSS; 115 mAudioManager.abandonAudioFocus(this); 116 } 117 118 /** Returns {@code true} if the device supports AC3 pass-through. */ 119 boolean isAc3PassthroughSupported() { 120 return mAc3PassthroughSupported; 121 } 122 123 /** Release the resources the helper class may occupied. */ 124 void release() { 125 mAudioCapabilitiesReceiver.unregister(); 126 } 127 128 @Override 129 public void onAudioFocusChange(int focusChange) { 130 mAudioFocusStatus = focusChange; 131 setVolumeByAudioFocusStatus(); 132 } 133 } 134