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
40    /**
41     * All parameters are guaranteed valid through the Builder.
42     */
43    private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags) {
44        mRule = rule;
45        mFormat = format;
46        mRouteFlags = routeFlags;
47        mRegistrationId = null;
48        mMixType = rule.getTargetMixType();
49    }
50
51    /**
52     * An audio mix behavior where the output of the mix is sent to the original destination of
53     * the audio signal, i.e. an output device for an output mix, or a recording for an input mix.
54     */
55    @SystemApi
56    public static final int ROUTE_FLAG_RENDER    = 0x1;
57    /**
58     * An audio mix behavior where the output of the mix is rerouted back to the framework and
59     * is accessible for injection or capture through the {@link AudioTrack} and {@link AudioRecord}
60     * APIs.
61     */
62    @SystemApi
63    public static final int ROUTE_FLAG_LOOP_BACK = 0x1 << 1;
64
65    /**
66     * @hide
67     * Invalid mix type, default value.
68     */
69    public static final int MIX_TYPE_INVALID = -1;
70    /**
71     * @hide
72     * Mix type indicating playback streams are mixed.
73     */
74    public static final int MIX_TYPE_PLAYERS = 0;
75    /**
76     * @hide
77     * Mix type indicating recording streams are mixed.
78     */
79    public static final int MIX_TYPE_RECORDERS = 1;
80
81    int getRouteFlags() {
82        return mRouteFlags;
83    }
84
85    AudioFormat getFormat() {
86        return mFormat;
87    }
88
89    AudioMixingRule getRule() {
90        return mRule;
91    }
92
93    /** @hide */
94    public int getMixType() {
95        return mMixType;
96    }
97
98    void setRegistration(String regId) {
99        mRegistrationId = regId;
100    }
101
102    /** @hide */
103    public String getRegistration() {
104        return mRegistrationId;
105    }
106
107    /** @hide */
108    @Override
109    public int hashCode() {
110        return Objects.hash(mRouteFlags, mRule, mMixType, mFormat);
111    }
112
113    /** @hide */
114    @IntDef(flag = true,
115            value = { ROUTE_FLAG_RENDER, ROUTE_FLAG_LOOP_BACK } )
116    @Retention(RetentionPolicy.SOURCE)
117    public @interface RouteFlags {}
118
119    /**
120     * Builder class for {@link AudioMix} objects
121     *
122     */
123    @SystemApi
124    public static class Builder {
125        private AudioMixingRule mRule = null;
126        private AudioFormat mFormat = null;
127        private int mRouteFlags = 0;
128
129        /**
130         * @hide
131         * Only used by AudioPolicyConfig, not a public API.
132         */
133        Builder() { }
134
135        /**
136         * Construct an instance for the given {@link AudioMixingRule}.
137         * @param rule a non-null {@link AudioMixingRule} instance.
138         * @throws IllegalArgumentException
139         */
140        @SystemApi
141        public Builder(AudioMixingRule rule)
142                throws IllegalArgumentException {
143            if (rule == null) {
144                throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
145            }
146            mRule = rule;
147        }
148
149        /**
150         * @hide
151         * Only used by AudioPolicyConfig, not a public API.
152         * @param rule
153         * @return the same Builder instance.
154         * @throws IllegalArgumentException
155         */
156        public Builder setMixingRule(AudioMixingRule rule)
157                throws IllegalArgumentException {
158            if (rule == null) {
159                throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
160            }
161            mRule = rule;
162            return this;
163        }
164
165        /**
166         * Sets the {@link AudioFormat} for the mix.
167         * @param format a non-null {@link AudioFormat} instance.
168         * @return the same Builder instance.
169         * @throws IllegalArgumentException
170         */
171        @SystemApi
172        public Builder setFormat(AudioFormat format)
173                throws IllegalArgumentException {
174            if (format == null) {
175                throw new IllegalArgumentException("Illegal null AudioFormat argument");
176            }
177            mFormat = format;
178            return this;
179        }
180
181        /**
182         * Sets the routing behavior for the mix.
183         * @param routeFlags one of {@link AudioMix#ROUTE_FLAG_LOOP_BACK},
184         *     {@link AudioMix#ROUTE_FLAG_RENDER}
185         * @return the same Builder instance.
186         * @throws IllegalArgumentException
187         */
188        @SystemApi
189        public Builder setRouteFlags(@RouteFlags int routeFlags)
190                throws IllegalArgumentException {
191            if (routeFlags == 0) {
192                throw new IllegalArgumentException("Illegal empty route flags");
193            }
194            if ((routeFlags & (ROUTE_FLAG_LOOP_BACK | ROUTE_FLAG_RENDER)) == 0) {
195                throw new IllegalArgumentException("Invalid route flags 0x"
196                        + Integer.toHexString(routeFlags) + "when creating an AudioMix");
197            }
198            mRouteFlags = routeFlags;
199            return this;
200        }
201
202        /**
203         * Combines all of the settings and return a new {@link AudioMix} object.
204         * @return a new {@link AudioMix} object
205         * @throws IllegalArgumentException if no {@link AudioMixingRule} has been set.
206         */
207        @SystemApi
208        public AudioMix build() throws IllegalArgumentException {
209            if (mRule == null) {
210                throw new IllegalArgumentException("Illegal null AudioMixingRule");
211            }
212            if (mRouteFlags == 0) {
213                // no route flags set, use default
214                mRouteFlags = ROUTE_FLAG_RENDER;
215            }
216            if (mFormat == null) {
217                int rate = AudioSystem.getPrimaryOutputSamplingRate();
218                if (rate <= 0) {
219                    rate = 44100;
220                }
221                mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
222            }
223            return new AudioMix(mRule, mFormat, mRouteFlags);
224        }
225    }
226}
227