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
17package android.media.audiopolicy;
18
19import android.annotation.IntDef;
20import android.annotation.SystemApi;
21import android.media.AudioFormat;
22import android.media.AudioSystem;
23
24import java.lang.annotation.Retention;
25import java.lang.annotation.RetentionPolicy;
26import java.util.Objects;
27
28/**
29 * @hide
30 */
31@SystemApi
32public 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     */
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
122    public int getMixState() {
123        return mMixState;
124    }
125
126
127    int getRouteFlags() {
128        return mRouteFlags;
129    }
130
131    AudioFormat getFormat() {
132        return mFormat;
133    }
134
135    AudioMixingRule getRule() {
136        return mRule;
137    }
138
139    /** @hide */
140    public int getMixType() {
141        return mMixType;
142    }
143
144    void setRegistration(String regId) {
145        mRegistrationId = regId;
146    }
147
148    /** @hide */
149    public String getRegistration() {
150        return mRegistrationId;
151    }
152
153    /** @hide */
154    @Override
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         */
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
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         */
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         */
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
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
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
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