1 /* 2 * Copyright (C) 2020 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; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.util.Arrays; 28 import java.util.Objects; 29 import java.util.stream.Collectors; 30 31 /** 32 * An AudioProfile is specific to an audio format and lists supported sampling rates and 33 * channel masks for that format. An {@link AudioDeviceInfo} has a list of supported AudioProfiles. 34 * There can be multiple profiles whose encoding format is the same. This usually happens when 35 * an encoding format is only supported when it is encapsulated by some particular encapsulation 36 * types. If there are multiple encapsulation types that can carry this encoding format, they will 37 * be reported in different audio profiles. The application can choose any of the encapsulation 38 * types. 39 */ 40 public class AudioProfile implements Parcelable { 41 /** 42 * No encapsulation type is specified. 43 */ 44 public static final int AUDIO_ENCAPSULATION_TYPE_NONE = 0; 45 /** 46 * Encapsulation format is defined in standard IEC 61937. 47 */ 48 public static final int AUDIO_ENCAPSULATION_TYPE_IEC61937 = 1; 49 50 /** @hide */ 51 @IntDef({ 52 AUDIO_ENCAPSULATION_TYPE_NONE, 53 AUDIO_ENCAPSULATION_TYPE_IEC61937, 54 }) 55 @Retention(RetentionPolicy.SOURCE) 56 public @interface EncapsulationType {} 57 58 private final int mFormat; 59 private final int[] mSamplingRates; 60 private final int[] mChannelMasks; 61 private final int[] mChannelIndexMasks; 62 private final int mEncapsulationType; 63 64 /** 65 * @hide 66 * Constructor from format, sampling rates, channel masks, channel index masks and 67 * encapsulation type. 68 * @param format the audio format 69 * @param samplingRates the supported sampling rates 70 * @param channelMasks the supported channel masks 71 * @param channelIndexMasks the supported channel index masks 72 * @param encapsulationType the encapsulation type of the encoding format 73 */ 74 @SystemApi AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks, @NonNull int[] channelIndexMasks, int encapsulationType)75 public AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks, 76 @NonNull int[] channelIndexMasks, int encapsulationType) { 77 mFormat = format; 78 mSamplingRates = samplingRates; 79 mChannelMasks = channelMasks; 80 mChannelIndexMasks = channelIndexMasks; 81 mEncapsulationType = encapsulationType; 82 } 83 84 /** 85 * @return the encoding format for this AudioProfile. 86 */ getFormat()87 public @AudioFormat.Encoding int getFormat() { 88 return mFormat; 89 } 90 91 /** 92 * @return an array of channel position masks that are associated with the encoding format. 93 */ getChannelMasks()94 public @NonNull int[] getChannelMasks() { 95 return mChannelMasks; 96 } 97 98 /** 99 * @return an array of channel index masks that are associated with the encoding format. 100 */ getChannelIndexMasks()101 public @NonNull int[] getChannelIndexMasks() { 102 return mChannelIndexMasks; 103 } 104 105 /** 106 * @return an array of sample rates that are associated with the encoding format. 107 */ getSampleRates()108 public @NonNull int[] getSampleRates() { 109 return mSamplingRates; 110 } 111 112 /** 113 * The encapsulation type indicates what encapsulation type is required when the framework is 114 * using this format when playing to a device exposing this audio profile. 115 * When encapsulation is required, only playback with {@link android.media.AudioTrack} API is 116 * supported. But playback with {@link android.media.MediaPlayer} is not. 117 * When an encapsulation type is required, the {@link AudioFormat} encoding selected when 118 * creating the {@link AudioTrack} must match the encapsulation type, e.g 119 * AudioFormat.ENCODING_IEC61937 for AUDIO_ENCAPSULATION_TYPE_IEC61937. 120 * 121 * @return an integer representing the encapsulation type 122 * 123 * @see #AUDIO_ENCAPSULATION_TYPE_NONE 124 * @see #AUDIO_ENCAPSULATION_TYPE_IEC61937 125 */ getEncapsulationType()126 public @EncapsulationType int getEncapsulationType() { 127 return mEncapsulationType; 128 } 129 130 @Override hashCode()131 public int hashCode() { 132 return Objects.hash(mFormat, Arrays.hashCode(mSamplingRates), 133 Arrays.hashCode(mChannelMasks), Arrays.hashCode(mChannelIndexMasks), 134 mEncapsulationType); 135 } 136 137 @Override equals(Object o)138 public boolean equals(Object o) { 139 if (this == o) return true; 140 if (o == null || getClass() != o.getClass()) return false; 141 142 AudioProfile that = (AudioProfile) o; 143 return ((mFormat == that.mFormat) 144 && (hasIdenticalElements(mSamplingRates, that.mSamplingRates)) 145 && (hasIdenticalElements(mChannelMasks, that.mChannelMasks)) 146 && (hasIdenticalElements(mChannelIndexMasks, that.mChannelIndexMasks)) 147 && (mEncapsulationType == that.mEncapsulationType)); 148 } 149 150 @Override toString()151 public String toString() { 152 StringBuilder sb = new StringBuilder("{"); 153 sb.append(AudioFormat.toLogFriendlyEncoding(mFormat)); 154 if (mSamplingRates != null && mSamplingRates.length > 0) { 155 sb.append(", sampling rates=").append(Arrays.toString(mSamplingRates)); 156 } 157 if (mChannelMasks != null && mChannelMasks.length > 0) { 158 sb.append(", channel masks=").append(toHexString(mChannelMasks)); 159 } 160 if (mChannelIndexMasks != null && mChannelIndexMasks.length > 0) { 161 sb.append(", channel index masks=").append(Arrays.toString(mChannelIndexMasks)); 162 } 163 sb.append(", encapsulation type=" + mEncapsulationType); 164 sb.append("}"); 165 return sb.toString(); 166 } 167 toHexString(int[] ints)168 private static String toHexString(int[] ints) { 169 if (ints == null || ints.length == 0) { 170 return ""; 171 } 172 return Arrays.stream(ints).mapToObj(anInt -> String.format("0x%02X", anInt)) 173 .collect(Collectors.joining(", ")); 174 } 175 hasIdenticalElements(int[] array1, int[] array2)176 private static boolean hasIdenticalElements(int[] array1, int[] array2) { 177 int[] sortedArray1 = Arrays.copyOf(array1, array1.length); 178 Arrays.sort(sortedArray1); 179 int[] sortedArray2 = Arrays.copyOf(array2, array2.length); 180 Arrays.sort(sortedArray2); 181 return Arrays.equals(sortedArray1, sortedArray2); 182 } 183 184 @Override describeContents()185 public int describeContents() { 186 return 0; 187 } 188 189 @Override writeToParcel(@onNull Parcel dest, int flags)190 public void writeToParcel(@NonNull Parcel dest, int flags) { 191 dest.writeInt(mFormat); 192 dest.writeIntArray(mSamplingRates); 193 dest.writeIntArray(mChannelMasks); 194 dest.writeIntArray(mChannelIndexMasks); 195 dest.writeInt(mEncapsulationType); 196 } 197 AudioProfile(@onNull Parcel in)198 private AudioProfile(@NonNull Parcel in) { 199 mFormat = in.readInt(); 200 mSamplingRates = in.createIntArray(); 201 mChannelMasks = in.createIntArray(); 202 mChannelIndexMasks = in.createIntArray(); 203 mEncapsulationType = in.readInt(); 204 } 205 206 public static final @NonNull Parcelable.Creator<AudioProfile> CREATOR = 207 new Parcelable.Creator<AudioProfile>() { 208 /** 209 * Rebuilds an AudioProfile previously stored with writeToParcel(). 210 * @param p Parcel object to read the AudioProfile from 211 * @return a new AudioProfile created from the data in the parcel 212 */ 213 public AudioProfile createFromParcel(Parcel p) { 214 return new AudioProfile(p); 215 } 216 217 public AudioProfile[] newArray(int size) { 218 return new AudioProfile[size]; 219 } 220 }; 221 } 222