/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth; import static android.bluetooth.BluetoothLeAudioCodecConfig.FRAME_DURATION_10000; import static android.bluetooth.BluetoothLeAudioCodecConfig.FRAME_DURATION_7500; import static android.bluetooth.BluetoothLeAudioCodecConfig.FRAME_DURATION_NONE; import static android.bluetooth.BluetoothLeAudioCodecConfig.FrameDuration; import static android.bluetooth.BluetoothLeAudioCodecConfig.SAMPLE_RATE_16000; import static android.bluetooth.BluetoothLeAudioCodecConfig.SAMPLE_RATE_24000; import static android.bluetooth.BluetoothLeAudioCodecConfig.SAMPLE_RATE_32000; import static android.bluetooth.BluetoothLeAudioCodecConfig.SAMPLE_RATE_44100; import static android.bluetooth.BluetoothLeAudioCodecConfig.SAMPLE_RATE_48000; import static android.bluetooth.BluetoothLeAudioCodecConfig.SAMPLE_RATE_8000; import static android.bluetooth.BluetoothLeAudioCodecConfig.SAMPLE_RATE_NONE; import static android.bluetooth.BluetoothLeAudioCodecConfig.SampleRate; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.bluetooth.BluetoothLeAudioCodecConfig.FrameDuration; import android.bluetooth.BluetoothLeAudioCodecConfig.SampleRate; import android.bluetooth.BluetoothUtils.TypeValueEntry; import android.os.Parcel; import android.os.Parcelable; import com.android.bluetooth.flags.Flags; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * A class representing the codec specific config metadata information defined in the Basic Audio * Profile. * * @hide */ @SystemApi public final class BluetoothLeAudioCodecConfigMetadata implements Parcelable { private static final int SAMPLING_FREQUENCY_TYPE = 0x01; private static final int FRAME_DURATION_TYPE = 0x02; private static final int AUDIO_CHANNEL_LOCATION_TYPE = 0x03; private static final int OCTETS_PER_FRAME_TYPE = 0x04; private final long mAudioLocation; private final @SampleRate int mSampleRate; private final @FrameDuration int mFrameDuration; private final int mOctetsPerFrame; private final byte[] mRawMetadata; /** Audio codec sampling frequency from metadata. */ private static final int CONFIG_SAMPLING_FREQUENCY_UNKNOWN = 0; private static final int CONFIG_SAMPLING_FREQUENCY_8000 = 0x01; private static final int CONFIG_SAMPLING_FREQUENCY_16000 = 0x03; private static final int CONFIG_SAMPLING_FREQUENCY_24000 = 0x05; private static final int CONFIG_SAMPLING_FREQUENCY_32000 = 0x06; private static final int CONFIG_SAMPLING_FREQUENCY_44100 = 0x07; private static final int CONFIG_SAMPLING_FREQUENCY_48000 = 0x08; private static final int CONFIG_SAMPLING_FREQUENCY_11025 = 0x09; private static final int CONFIG_SAMPLING_FREQUENCY_22050 = 0x0a; private static final int CONFIG_SAMPLING_FREQUENCY_88200 = 0x0b; private static final int CONFIG_SAMPLING_FREQUENCY_96000 = 0x0c; private static final int CONFIG_SAMPLING_FREQUENCY_176400 = 0x0d; private static final int CONFIG_SAMPLING_FREQUENCY_192000 = 0x0e; private static final int CONFIG_SAMPLING_FREQUENCY_384000 = 0x0f; /** Audio codec config frame duration from metadata. */ private static final int CONFIG_FRAME_DURATION_UNKNOWN = -1; private static final int CONFIG_FRAME_DURATION_7500 = 0x00; private static final int CONFIG_FRAME_DURATION_10000 = 0x01; private BluetoothLeAudioCodecConfigMetadata( long audioLocation, @SampleRate int sampleRate, @FrameDuration int frameDuration, int octetsPerFrame, byte[] rawMetadata) { mAudioLocation = audioLocation; mSampleRate = sampleRate; mFrameDuration = frameDuration; mOctetsPerFrame = octetsPerFrame; mRawMetadata = rawMetadata; } @Override public boolean equals(@Nullable Object o) { if (o != null && o instanceof BluetoothLeAudioCodecConfigMetadata) { final BluetoothLeAudioCodecConfigMetadata oth = (BluetoothLeAudioCodecConfigMetadata) o; return mAudioLocation == oth.getAudioLocation() && mSampleRate == oth.getSampleRate() && mFrameDuration == oth.getFrameDuration() && mOctetsPerFrame == oth.getOctetsPerFrame() && Arrays.equals(mRawMetadata, oth.getRawMetadata()); } return false; } @Override public int hashCode() { return Objects.hash( mAudioLocation, mSampleRate, mFrameDuration, mOctetsPerFrame, Arrays.hashCode(mRawMetadata)); } @Override public String toString() { return "BluetoothLeAudioCodecConfigMetadata{" + ("audioLocation=" + mAudioLocation) + (", sampleRate=" + mSampleRate) + (", frameDuration=" + mFrameDuration) + (", octetsPerFrame=" + mOctetsPerFrame) + (", rawMetadata=" + Arrays.toString(mRawMetadata)) + '}'; } /** * Get the audio location information as defined in the Generic Audio section of Bluetooth * Assigned numbers. * * @return configured audio location, -1 if this metadata does not exist * @hide */ @SystemApi public long getAudioLocation() { return mAudioLocation; } /** * Get the audio sample rate information as defined in the Generic Audio section of Bluetooth * Assigned numbers 6.12.4.1 Supported_Sampling_Frequencies. * *
Internally this is converted from Sampling_Frequency values as defined in 6.12.5.1 * * @return configured sample rate from meta data, {@link * BluetoothLeAudioCodecConfig#SAMPLE_RATE_NONE} if this metadata does not exist * @hide */ @SystemApi public @SampleRate int getSampleRate() { return mSampleRate; } /** * Get the audio frame duration information as defined in the Generic Audio section of Bluetooth * Assigned numbers 6.12.5.2 Frame_Duration. * *
Internally this is converted from Frame_Durations values as defined in 6.12.4.2 * * @return configured frame duration from meta data, {@link * BluetoothLeAudioCodecConfig#FRAME_DURATION_NONE} if this metadata does not exist * @hide */ @SystemApi public @FrameDuration int getFrameDuration() { return mFrameDuration; } /** * Get the audio octets per frame information as defined in the Generic Audio section of * Bluetooth Assigned numbers. * * @return configured octets per frame from meta data 0 if this metadata does not exist * @hide */ @SystemApi public int getOctetsPerFrame() { return mOctetsPerFrame; } /** * Get the raw bytes of stream metadata in Bluetooth LTV format. * *
Bluetooth LTV format for stream metadata is defined in the Generic Audio section of Bluetooth Assigned
* Numbers, including metadata that was not covered by the getter methods in this class.
*
* @return raw bytes of stream metadata in Bluetooth LTV format
* @hide
*/
@SystemApi
public @NonNull byte[] getRawMetadata() {
return mRawMetadata;
}
/**
* {@inheritDoc}
*
* @hide
*/
@Override
public int describeContents() {
return 0;
}
/**
* {@inheritDoc}
*
* @hide
*/
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mAudioLocation);
if (mRawMetadata != null) {
out.writeInt(mRawMetadata.length);
out.writeByteArray(mRawMetadata);
} else {
out.writeInt(-1);
}
out.writeInt(mSampleRate);
out.writeInt(mFrameDuration);
out.writeInt(mOctetsPerFrame);
}
/**
* A {@link Parcelable.Creator} to create {@link BluetoothLeAudioCodecConfigMetadata} from
* parcel.
*
* @hide
*/
@SystemApi @NonNull
public static final Creator The byte array will be parsed and values for each getter will be populated
*
* Raw metadata cannot be set using builder in order to maintain raw bytes and getter value
* consistency
*
* @param rawBytes raw bytes of stream metadata in Bluetooth LTV format
* @return parsed {@link BluetoothLeAudioCodecConfigMetadata} object
* @throws IllegalArgumentException if rawBytes is null or when the raw bytes cannot
* be parsed to build the object
* @hide
*/
@SystemApi
@NonNull
public static BluetoothLeAudioCodecConfigMetadata fromRawBytes(@NonNull byte[] rawBytes) {
if (rawBytes == null) {
throw new IllegalArgumentException("Raw bytes cannot be null");
}
List Internally this will be converted to Sampling_Frequency values as defined in 6.12.5.1
*
* @param sampleRate configured sample rate in meta data
* @return this builder
* @throws IllegalArgumentException if sample rate is invalid value
* @hide
*/
@SystemApi
@NonNull
public Builder setSampleRate(@SampleRate int sampleRate) {
if (sampleRate != SAMPLE_RATE_NONE
&& sampleRate != SAMPLE_RATE_8000
&& sampleRate != SAMPLE_RATE_16000
&& sampleRate != SAMPLE_RATE_24000
&& sampleRate != SAMPLE_RATE_32000
&& sampleRate != SAMPLE_RATE_44100
&& sampleRate != SAMPLE_RATE_48000) {
if (Flags.leaudioAddSamplingFrequencies()) {
if (sampleRate != BluetoothLeAudioCodecConfig.SAMPLE_RATE_11025
&& sampleRate != BluetoothLeAudioCodecConfig.SAMPLE_RATE_22050
&& sampleRate != BluetoothLeAudioCodecConfig.SAMPLE_RATE_88200
&& sampleRate != BluetoothLeAudioCodecConfig.SAMPLE_RATE_96000
&& sampleRate != BluetoothLeAudioCodecConfig.SAMPLE_RATE_176400
&& sampleRate != BluetoothLeAudioCodecConfig.SAMPLE_RATE_192000
&& sampleRate != BluetoothLeAudioCodecConfig.SAMPLE_RATE_384000) {
throw new IllegalArgumentException("Invalid sample rate " + sampleRate);
}
} else {
throw new IllegalArgumentException("Invalid sample rate " + sampleRate);
}
}
mSampleRate = sampleRate;
return this;
}
/**
* Set the audio frame duration information as defined in the Generic Audio section of
* Bluetooth Assigned numbers 6.12.5.2 Frame_Duration.
*
* Internally this will be converted to Frame_Durations values as defined in 6.12.4.2
*
* @param frameDuration configured frame duration in meta data
* @return this builder
* @throws IllegalArgumentException if frameDuration is invalid value
* @hide
*/
@SystemApi
@NonNull
public Builder setFrameDuration(@FrameDuration int frameDuration) {
if (frameDuration != FRAME_DURATION_NONE
&& frameDuration != FRAME_DURATION_7500
&& frameDuration != FRAME_DURATION_10000) {
throw new IllegalArgumentException("Invalid frame duration " + frameDuration);
}
mFrameDuration = frameDuration;
return this;
}
/**
* Set the audio octets per frame information as defined in the Generic Audio section of
* Bluetooth Assigned numbers.
*
* @param octetsPerFrame configured octets per frame in meta data
* @return this builder
* @throws IllegalArgumentException if octetsPerFrame is invalid value
* @hide
*/
@SystemApi
@NonNull
public Builder setOctetsPerFrame(int octetsPerFrame) {
if (octetsPerFrame < 0) {
throw new IllegalArgumentException("Invalid octetsPerFrame " + octetsPerFrame);
}
mOctetsPerFrame = octetsPerFrame;
return this;
}
/**
* Build {@link BluetoothLeAudioCodecConfigMetadata}.
*
* @return constructed {@link BluetoothLeAudioCodecConfigMetadata}
* @throws IllegalArgumentException if the object cannot be built
* @hide
*/
@SystemApi
public @NonNull BluetoothLeAudioCodecConfigMetadata build() {
List