1 /*
2  * Copyright (C) 2014 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 package android.media.audiopolicy;
18 
19 import android.annotation.IntDef;
20 import android.annotation.SystemApi;
21 import android.media.AudioFormat;
22 import android.media.AudioSystem;
23 
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 import java.util.Objects;
27 
28 /**
29  * @hide
30  */
31 @SystemApi
32 public class AudioMix {
33 
34     private AudioMixingRule mRule;
35     private AudioFormat mFormat;
36     private int mRouteFlags;
37     private String mRegistrationId;
38     private int mMixType = MIX_TYPE_INVALID;
39     int mMixState = MIX_STATE_DISABLED;
40     int mCallbackFlags;
41 
42     /**
43      * All parameters are guaranteed valid through the Builder.
44      */
AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags)45     private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags) {
46         mRule = rule;
47         mFormat = format;
48         mRouteFlags = routeFlags;
49         mRegistrationId = null;
50         mMixType = rule.getTargetMixType();
51         mCallbackFlags = callbackFlags;
52     }
53 
54     // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
55     // in frameworks/av/include/media/AudioPolicy.h
56     /** @hide */
57     public final static int CALLBACK_FLAG_NOTIFY_ACTIVITY = 0x1;
58     // when adding new MIX_FLAG_* flags, add them to this mask of authorized masks:
59     private final static int CALLBACK_FLAGS_ALL = CALLBACK_FLAG_NOTIFY_ACTIVITY;
60 
61     // ROUTE_FLAG_* values: keep in sync with MIX_ROUTE_FLAG_* values defined
62     // in frameworks/av/include/media/AudioPolicy.h
63     /**
64      * An audio mix behavior where the output of the mix is sent to the original destination of
65      * the audio signal, i.e. an output device for an output mix, or a recording for an input mix.
66      */
67     @SystemApi
68     public static final int ROUTE_FLAG_RENDER    = 0x1;
69     /**
70      * An audio mix behavior where the output of the mix is rerouted back to the framework and
71      * is accessible for injection or capture through the {@link AudioTrack} and {@link AudioRecord}
72      * APIs.
73      */
74     @SystemApi
75     public static final int ROUTE_FLAG_LOOP_BACK = 0x1 << 1;
76 
77     // MIX_TYPE_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h
78     /**
79      * @hide
80      * Invalid mix type, default value.
81      */
82     public static final int MIX_TYPE_INVALID = -1;
83     /**
84      * @hide
85      * Mix type indicating playback streams are mixed.
86      */
87     public static final int MIX_TYPE_PLAYERS = 0;
88     /**
89      * @hide
90      * Mix type indicating recording streams are mixed.
91      */
92     public static final int MIX_TYPE_RECORDERS = 1;
93 
94 
95     // MIX_STATE_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h
96     /**
97      * @hide
98      * State of a mix before its policy is enabled.
99      */
100     @SystemApi
101     public static final int MIX_STATE_DISABLED = -1;
102     /**
103      * @hide
104      * State of a mix when there is no audio to mix.
105      */
106     @SystemApi
107     public static final int MIX_STATE_IDLE = 0;
108     /**
109      * @hide
110      * State of a mix that is actively mixing audio.
111      */
112     @SystemApi
113     public static final int MIX_STATE_MIXING = 1;
114 
115     /**
116      * @hide
117      * The current mixing state.
118      * @return one of {@link #MIX_STATE_DISABLED}, {@link #MIX_STATE_IDLE},
119      *          {@link #MIX_STATE_MIXING}.
120      */
121     @SystemApi
getMixState()122     public int getMixState() {
123         return mMixState;
124     }
125 
126 
getRouteFlags()127     int getRouteFlags() {
128         return mRouteFlags;
129     }
130 
getFormat()131     AudioFormat getFormat() {
132         return mFormat;
133     }
134 
getRule()135     AudioMixingRule getRule() {
136         return mRule;
137     }
138 
139     /** @hide */
getMixType()140     public int getMixType() {
141         return mMixType;
142     }
143 
setRegistration(String regId)144     void setRegistration(String regId) {
145         mRegistrationId = regId;
146     }
147 
148     /** @hide */
getRegistration()149     public String getRegistration() {
150         return mRegistrationId;
151     }
152 
153     /** @hide */
154     @Override
hashCode()155     public int hashCode() {
156         return Objects.hash(mRouteFlags, mRule, mMixType, mFormat);
157     }
158 
159     /** @hide */
160     @IntDef(flag = true,
161             value = { ROUTE_FLAG_RENDER, ROUTE_FLAG_LOOP_BACK } )
162     @Retention(RetentionPolicy.SOURCE)
163     public @interface RouteFlags {}
164 
165     /**
166      * Builder class for {@link AudioMix} objects
167      *
168      */
169     @SystemApi
170     public static class Builder {
171         private AudioMixingRule mRule = null;
172         private AudioFormat mFormat = null;
173         private int mRouteFlags = 0;
174         private int mCallbackFlags = 0;
175 
176         /**
177          * @hide
178          * Only used by AudioPolicyConfig, not a public API.
179          */
Builder()180         Builder() { }
181 
182         /**
183          * Construct an instance for the given {@link AudioMixingRule}.
184          * @param rule a non-null {@link AudioMixingRule} instance.
185          * @throws IllegalArgumentException
186          */
187         @SystemApi
Builder(AudioMixingRule rule)188         public Builder(AudioMixingRule rule)
189                 throws IllegalArgumentException {
190             if (rule == null) {
191                 throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
192             }
193             mRule = rule;
194         }
195 
196         /**
197          * @hide
198          * Only used by AudioPolicyConfig, not a public API.
199          * @param rule
200          * @return the same Builder instance.
201          * @throws IllegalArgumentException
202          */
setMixingRule(AudioMixingRule rule)203         public Builder setMixingRule(AudioMixingRule rule)
204                 throws IllegalArgumentException {
205             if (rule == null) {
206                 throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
207             }
208             mRule = rule;
209             return this;
210         }
211 
212         /**
213          * @hide
214          * Only used by AudioPolicyConfig, not a public API.
215          * @param callbackFlags which callbacks are called from native
216          * @return the same Builder instance.
217          * @throws IllegalArgumentException
218          */
setCallbackFlags(int flags)219         public Builder setCallbackFlags(int flags) throws IllegalArgumentException {
220             if ((flags != 0) && ((flags & CALLBACK_FLAGS_ALL) == 0)) {
221                 throw new IllegalArgumentException("Illegal callback flags 0x"
222                         + Integer.toHexString(flags).toUpperCase());
223             }
224             mCallbackFlags = flags;
225             return this;
226         }
227 
228         /**
229          * Sets the {@link AudioFormat} for the mix.
230          * @param format a non-null {@link AudioFormat} instance.
231          * @return the same Builder instance.
232          * @throws IllegalArgumentException
233          */
234         @SystemApi
setFormat(AudioFormat format)235         public Builder setFormat(AudioFormat format)
236                 throws IllegalArgumentException {
237             if (format == null) {
238                 throw new IllegalArgumentException("Illegal null AudioFormat argument");
239             }
240             mFormat = format;
241             return this;
242         }
243 
244         /**
245          * Sets the routing behavior for the mix.
246          * @param routeFlags one of {@link AudioMix#ROUTE_FLAG_LOOP_BACK},
247          *     {@link AudioMix#ROUTE_FLAG_RENDER}
248          * @return the same Builder instance.
249          * @throws IllegalArgumentException
250          */
251         @SystemApi
setRouteFlags(@outeFlags int routeFlags)252         public Builder setRouteFlags(@RouteFlags int routeFlags)
253                 throws IllegalArgumentException {
254             if (routeFlags == 0) {
255                 throw new IllegalArgumentException("Illegal empty route flags");
256             }
257             if ((routeFlags & (ROUTE_FLAG_LOOP_BACK | ROUTE_FLAG_RENDER)) == 0) {
258                 throw new IllegalArgumentException("Invalid route flags 0x"
259                         + Integer.toHexString(routeFlags) + "when creating an AudioMix");
260             }
261             mRouteFlags = routeFlags;
262             return this;
263         }
264 
265         /**
266          * Combines all of the settings and return a new {@link AudioMix} object.
267          * @return a new {@link AudioMix} object
268          * @throws IllegalArgumentException if no {@link AudioMixingRule} has been set.
269          */
270         @SystemApi
build()271         public AudioMix build() throws IllegalArgumentException {
272             if (mRule == null) {
273                 throw new IllegalArgumentException("Illegal null AudioMixingRule");
274             }
275             if (mRouteFlags == 0) {
276                 // no route flags set, use default
277                 mRouteFlags = ROUTE_FLAG_RENDER;
278             }
279             if (mFormat == null) {
280                 int rate = AudioSystem.getPrimaryOutputSamplingRate();
281                 if (rate <= 0) {
282                     rate = 44100;
283                 }
284                 mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
285             }
286             return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags);
287         }
288     }
289 }
290