1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.chromecast.shell;
6 
7 import android.media.AudioAttributes;
8 import android.media.AudioFocusRequest;
9 import android.media.AudioManager;
10 import android.os.Build;
11 
12 import androidx.annotation.NonNull;
13 
14 import org.chromium.base.Log;
15 
16 import java.util.HashSet;
17 import java.util.Set;
18 
19 /**
20  * Wrapper for Cast code to pass parameter to AudioFocus methods.
21  * This maintains backwards compatibility with old APIs - requestAudioFocus() and
22  * abandonAudioFocus()
23  */
24 public class CastAudioFocusRequest {
25     private static final String TAG = "CastAudioFocus";
26     private AudioFocusRequest mAudioFocusRequest;
27     private AudioAttributes mAudioAttributes;
28     private int mFocusGain;
29     private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener;
30 
CastAudioFocusRequest(AudioFocusRequest audioFocusRequest)31     CastAudioFocusRequest(AudioFocusRequest audioFocusRequest) {
32         mAudioFocusRequest = audioFocusRequest;
33     }
34 
CastAudioFocusRequest(AudioAttributes audioAttributes, int focusGain, AudioManager.OnAudioFocusChangeListener l)35     CastAudioFocusRequest(AudioAttributes audioAttributes, int focusGain,
36             AudioManager.OnAudioFocusChangeListener l) {
37         mAudioAttributes = audioAttributes;
38         mFocusGain = focusGain;
39         mAudioFocusChangeListener = l;
40     }
41 
getAudioFocusRequest()42     AudioFocusRequest getAudioFocusRequest() {
43         return mAudioFocusRequest;
44     }
45 
getStreamType()46     private int getStreamType() {
47         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
48             if (mAudioAttributes != null) {
49                 switch (mAudioAttributes.getContentType()) {
50                     case AudioAttributes.CONTENT_TYPE_MOVIE:
51                     case AudioAttributes.CONTENT_TYPE_MUSIC:
52                         return AudioManager.STREAM_MUSIC;
53                     case AudioAttributes.CONTENT_TYPE_SONIFICATION:
54                         return AudioManager.STREAM_ALARM;
55                     case AudioAttributes.CONTENT_TYPE_SPEECH:
56                         return AudioManager.STREAM_VOICE_CALL;
57                     case AudioAttributes.CONTENT_TYPE_UNKNOWN:
58                     default:
59                         return AudioManager.STREAM_SYSTEM;
60                 }
61             }
62         }
63         return 0;
64     }
65 
setAudioFocusChangeListener(AudioManager.OnAudioFocusChangeListener l)66     void setAudioFocusChangeListener(AudioManager.OnAudioFocusChangeListener l) {
67         mAudioFocusChangeListener = l;
68         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && mAudioFocusRequest != null) {
69             mAudioFocusRequest = new AudioFocusRequest.Builder(mAudioFocusRequest)
70                                          .setOnAudioFocusChangeListener(mAudioFocusChangeListener)
71                                          .build();
72         }
73     }
74 
request(AudioManager audioManager)75     int request(AudioManager audioManager) {
76         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
77             return audioManager.requestAudioFocus(mAudioFocusRequest);
78         } else {
79             return audioManager.requestAudioFocus(
80                     mAudioFocusChangeListener, getStreamType(), mFocusGain);
81         }
82     }
83 
abandon(AudioManager audioManager)84     int abandon(AudioManager audioManager) {
85         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
86             return audioManager.abandonAudioFocusRequest(mAudioFocusRequest);
87         } else {
88             return audioManager.abandonAudioFocus(mAudioFocusChangeListener);
89         }
90     }
91 
92     /**
93      * Backwards compatible builder method to create CastAudioFocusRequest object.
94      */
95     public static class Builder {
96         private AudioAttributes mAudioAttributes;
97         private int mFocusGain;
98         private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener;
99         private Set<Integer> mValidFocusGainValues;
100 
Builder()101         public Builder() {
102             mAudioAttributes = null;
103             mFocusGain = 0;
104             mAudioFocusChangeListener = null;
105             mValidFocusGainValues = new HashSet<Integer>();
106             mValidFocusGainValues.add(AudioManager.AUDIOFOCUS_GAIN);
107             mValidFocusGainValues.add(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
108             mValidFocusGainValues.add(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
109             mValidFocusGainValues.add(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);
110         }
111 
setAudioAttributes(@onNull AudioAttributes audioAttributes)112         public @NonNull Builder setAudioAttributes(@NonNull AudioAttributes audioAttributes) {
113             mAudioAttributes = audioAttributes;
114             return this;
115         }
116 
setFocusGain(int focusGain)117         public @NonNull Builder setFocusGain(int focusGain) {
118             if (mValidFocusGainValues.contains(focusGain)) {
119                 mFocusGain = focusGain;
120             } else {
121                 Log.e(TAG, "Invalid focus gain value " + focusGain);
122                 mFocusGain = AudioManager.AUDIOFOCUS_GAIN;
123             }
124             return this;
125         }
126 
setAudioFocusChangeListener( AudioManager.OnAudioFocusChangeListener l)127         public @NonNull Builder setAudioFocusChangeListener(
128                 AudioManager.OnAudioFocusChangeListener l) {
129             mAudioFocusChangeListener = l;
130             return this;
131         }
132 
build()133         public CastAudioFocusRequest build() {
134             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
135                 AudioFocusRequest.Builder builder = new AudioFocusRequest.Builder(mFocusGain);
136                 if (mAudioAttributes != null) {
137                     builder = builder.setAudioAttributes(mAudioAttributes);
138                 }
139                 if (mAudioFocusChangeListener != null) {
140                     builder = builder.setOnAudioFocusChangeListener(mAudioFocusChangeListener);
141                 }
142                 AudioFocusRequest audioFocusRequest = builder.build();
143                 return new CastAudioFocusRequest(audioFocusRequest);
144             } else {
145                 return new CastAudioFocusRequest(
146                         mAudioAttributes, mFocusGain, mAudioFocusChangeListener);
147             }
148         }
149     }
150 }
151