Home | History | Annotate | Download | only in tv
      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