1/*
2 * Copyright (C) 2016 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;
18
19import android.annotation.IntDef;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.util.Log;
23
24import java.lang.annotation.Retention;
25import java.lang.annotation.RetentionPolicy;
26import java.util.ArrayList;
27import java.util.Objects;
28
29/**
30 * The AudioRecordingConfiguration class collects the information describing an audio recording
31 * session. This information is returned through the
32 * {@link AudioManager#getActiveRecordingConfigurations()} method.
33 *
34 */
35public final class AudioRecordingConfiguration implements Parcelable {
36    private final static String TAG = new String("AudioRecordingConfiguration");
37
38    private final int mSessionId;
39
40    private final int mClientSource;
41
42    private final AudioFormat mDeviceFormat;
43    private final AudioFormat mClientFormat;
44
45    private final int mPatchHandle;
46
47    /**
48     * @hide
49     */
50    public AudioRecordingConfiguration(int session, int source, AudioFormat devFormat,
51            AudioFormat clientFormat, int patchHandle) {
52        mSessionId = session;
53        mClientSource = source;
54        mDeviceFormat = devFormat;
55        mClientFormat = clientFormat;
56        mPatchHandle = patchHandle;
57    }
58
59    // matches the sources that return false in MediaRecorder.isSystemOnlyAudioSource(source)
60    /** @hide */
61    @IntDef({
62        MediaRecorder.AudioSource.DEFAULT,
63        MediaRecorder.AudioSource.MIC,
64        MediaRecorder.AudioSource.VOICE_UPLINK,
65        MediaRecorder.AudioSource.VOICE_DOWNLINK,
66        MediaRecorder.AudioSource.VOICE_CALL,
67        MediaRecorder.AudioSource.CAMCORDER,
68        MediaRecorder.AudioSource.VOICE_RECOGNITION,
69        MediaRecorder.AudioSource.VOICE_COMMUNICATION,
70        MediaRecorder.AudioSource.UNPROCESSED
71    })
72    @Retention(RetentionPolicy.SOURCE)
73    public @interface AudioSource {}
74
75    // documented return values match the sources that return false
76    //   in MediaRecorder.isSystemOnlyAudioSource(source)
77    /**
78     * Returns the audio source being used for the recording.
79     * @return one of {@link MediaRecorder.AudioSource#DEFAULT},
80     *       {@link MediaRecorder.AudioSource#MIC},
81     *       {@link MediaRecorder.AudioSource#VOICE_UPLINK},
82     *       {@link MediaRecorder.AudioSource#VOICE_DOWNLINK},
83     *       {@link MediaRecorder.AudioSource#VOICE_CALL},
84     *       {@link MediaRecorder.AudioSource#CAMCORDER},
85     *       {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
86     *       {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION},
87     *       {@link MediaRecorder.AudioSource#UNPROCESSED}.
88     */
89    public @AudioSource int getClientAudioSource() { return mClientSource; }
90
91    /**
92     * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
93     * @return the session number.
94     */
95    public int getClientAudioSessionId() { return mSessionId; }
96
97    /**
98     * Returns the audio format at which audio is recorded on this Android device.
99     * Note that it may differ from the client application recording format
100     * (see {@link #getClientFormat()}).
101     * @return the device recording format
102     */
103    public AudioFormat getFormat() { return mDeviceFormat; }
104
105    /**
106     * Returns the audio format at which the client application is recording audio.
107     * Note that it may differ from the actual recording format (see {@link #getFormat()}).
108     * @return the recording format
109     */
110    public AudioFormat getClientFormat() { return mClientFormat; }
111
112    /**
113     * Returns information about the audio input device used for this recording.
114     * @return the audio recording device or null if this information cannot be retrieved
115     */
116    public AudioDeviceInfo getAudioDevice() {
117        // build the AudioDeviceInfo from the patch handle
118        ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
119        if (AudioManager.listAudioPatches(patches) != AudioManager.SUCCESS) {
120            Log.e(TAG, "Error retrieving list of audio patches");
121            return null;
122        }
123        for (int i = 0 ; i < patches.size() ; i++) {
124            final AudioPatch patch = patches.get(i);
125            if (patch.id() == mPatchHandle) {
126                final AudioPortConfig[] sources = patch.sources();
127                if ((sources != null) && (sources.length > 0)) {
128                    // not supporting multiple sources, so just look at the first source
129                    final int devId = sources[0].port().id();
130                    final AudioDeviceInfo[] devices =
131                            AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
132                    for (int j = 0; j < devices.length; j++) {
133                        if (devices[j].getId() == devId) {
134                            return devices[j];
135                        }
136                    }
137                }
138                // patch handle is unique, there won't be another with the same handle
139                break;
140            }
141        }
142        Log.e(TAG, "Couldn't find device for recording, did recording end already?");
143        return null;
144    }
145
146    public static final Parcelable.Creator<AudioRecordingConfiguration> CREATOR
147            = new Parcelable.Creator<AudioRecordingConfiguration>() {
148        /**
149         * Rebuilds an AudioRecordingConfiguration previously stored with writeToParcel().
150         * @param p Parcel object to read the AudioRecordingConfiguration from
151         * @return a new AudioRecordingConfiguration created from the data in the parcel
152         */
153        public AudioRecordingConfiguration createFromParcel(Parcel p) {
154            return new AudioRecordingConfiguration(p);
155        }
156        public AudioRecordingConfiguration[] newArray(int size) {
157            return new AudioRecordingConfiguration[size];
158        }
159    };
160
161    @Override
162    public int hashCode() {
163        return Objects.hash(mSessionId, mClientSource);
164    }
165
166    @Override
167    public int describeContents() {
168        return 0;
169    }
170
171    @Override
172    public void writeToParcel(Parcel dest, int flags) {
173        dest.writeInt(mSessionId);
174        dest.writeInt(mClientSource);
175        mClientFormat.writeToParcel(dest, 0);
176        mDeviceFormat.writeToParcel(dest, 0);
177        dest.writeInt(mPatchHandle);
178    }
179
180    private AudioRecordingConfiguration(Parcel in) {
181        mSessionId = in.readInt();
182        mClientSource = in.readInt();
183        mClientFormat = AudioFormat.CREATOR.createFromParcel(in);
184        mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in);
185        mPatchHandle = in.readInt();
186    }
187
188    @Override
189    public boolean equals(Object o) {
190        if (this == o) return true;
191        if (o == null || !(o instanceof AudioRecordingConfiguration)) return false;
192
193        AudioRecordingConfiguration that = (AudioRecordingConfiguration) o;
194
195        return ((mSessionId == that.mSessionId)
196                && (mClientSource == that.mClientSource)
197                && (mPatchHandle == that.mPatchHandle)
198                && (mClientFormat.equals(that.mClientFormat))
199                && (mDeviceFormat.equals(that.mDeviceFormat)));
200    }
201}