AudioFormat: Add ENCODING_PCM_32BIT ENCODING_PCM_24BIT_PACKED

Add extended high definition integer formats to support direct
audio data delivery to the HAL.

Test: atest AudioRecordTest
Test: atest AudioTrackTest
Test: Clarity AudioManager
Bug: 152481314
Bug: 157671580
Change-Id: I92a099e98dd20ef900765928cbacea5e8a940c3c
This commit is contained in:
Andy Hung
2020-11-10 09:12:01 -08:00
parent fded2b6d13
commit cec9647e0f
7 changed files with 129 additions and 29 deletions

View File

@@ -24358,6 +24358,8 @@ package android.media {
field public static final int ENCODING_MP3 = 9; // 0x9 field public static final int ENCODING_MP3 = 9; // 0x9
field public static final int ENCODING_OPUS = 20; // 0x14 field public static final int ENCODING_OPUS = 20; // 0x14
field public static final int ENCODING_PCM_16BIT = 2; // 0x2 field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_24BIT_PACKED = 21; // 0x15
field public static final int ENCODING_PCM_32BIT = 22; // 0x16
field public static final int ENCODING_PCM_8BIT = 3; // 0x3 field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4 field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0 field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0

View File

@@ -24340,6 +24340,8 @@ package android.media {
field public static final int ENCODING_MP3 = 9; // 0x9 field public static final int ENCODING_MP3 = 9; // 0x9
field public static final int ENCODING_OPUS = 20; // 0x14 field public static final int ENCODING_OPUS = 20; // 0x14
field public static final int ENCODING_PCM_16BIT = 2; // 0x2 field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_24BIT_PACKED = 21; // 0x15
field public static final int ENCODING_PCM_32BIT = 22; // 0x16
field public static final int ENCODING_PCM_8BIT = 3; // 0x3 field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4 field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0 field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0

View File

@@ -39,6 +39,8 @@
#define ENCODING_E_AC3_JOC 18 #define ENCODING_E_AC3_JOC 18
#define ENCODING_DOLBY_MAT 19 #define ENCODING_DOLBY_MAT 19
#define ENCODING_OPUS 20 #define ENCODING_OPUS 20
#define ENCODING_PCM_24BIT_PACKED 21
#define ENCODING_PCM_32BIT 22
#define ENCODING_INVALID 0 #define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1 #define ENCODING_DEFAULT 1
@@ -92,6 +94,10 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_MAT; return AUDIO_FORMAT_MAT;
case ENCODING_OPUS: case ENCODING_OPUS:
return AUDIO_FORMAT_OPUS; return AUDIO_FORMAT_OPUS;
case ENCODING_PCM_24BIT_PACKED:
return AUDIO_FORMAT_PCM_24_BIT_PACKED;
case ENCODING_PCM_32BIT:
return AUDIO_FORMAT_PCM_32_BIT;
default: default:
return AUDIO_FORMAT_INVALID; return AUDIO_FORMAT_INVALID;
} }
@@ -107,10 +113,15 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
case AUDIO_FORMAT_PCM_FLOAT: case AUDIO_FORMAT_PCM_FLOAT:
return ENCODING_PCM_FLOAT; return ENCODING_PCM_FLOAT;
// map these to ENCODING_PCM_FLOAT // As of S, these extend integer precision formats now return more specific values
case AUDIO_FORMAT_PCM_8_24_BIT: // than ENCODING_PCM_FLOAT.
case AUDIO_FORMAT_PCM_24_BIT_PACKED: case AUDIO_FORMAT_PCM_24_BIT_PACKED:
return ENCODING_PCM_24BIT_PACKED;
case AUDIO_FORMAT_PCM_32_BIT: case AUDIO_FORMAT_PCM_32_BIT:
return ENCODING_PCM_32BIT;
// map this to ENCODING_PCM_FLOAT
case AUDIO_FORMAT_PCM_8_24_BIT:
return ENCODING_PCM_FLOAT; return ENCODING_PCM_FLOAT;
case AUDIO_FORMAT_AC3: case AUDIO_FORMAT_AC3:

View File

@@ -22,6 +22,7 @@ import android.util.SparseIntArray;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import java.util.TreeSet; import java.util.TreeSet;
@@ -468,9 +469,32 @@ public final class AudioDeviceInfo {
* @see AudioFormat * @see AudioFormat
* *
* Note: an empty array indicates that the device supports arbitrary encodings. * Note: an empty array indicates that the device supports arbitrary encodings.
* For forward compatibility, applications should ignore entries it does not recognize.
*/ */
public @NonNull int[] getEncodings() { public @NonNull int[] getEncodings() {
return AudioFormat.filterPublicFormats(mPort.formats()); final int[] encodings = AudioFormat.filterPublicFormats(mPort.formats());
boolean hasFloat = false;
boolean hasExtendedIntegerPrecision = false;
for (int encoding : encodings) {
if (AudioFormat.isEncodingLinearPcm(encoding)) {
if (encoding == AudioFormat.ENCODING_PCM_FLOAT) {
hasFloat = true;
} else if (AudioFormat.getBytesPerSample(encoding) > 2) {
hasExtendedIntegerPrecision = true;
}
}
}
if (hasExtendedIntegerPrecision && !hasFloat) {
// R and earlier compatibility - add ENCODING_PCM_FLOAT to the end
// (replacing the zero pad). This ensures pre-S apps that look
// for ENCODING_PCM_FLOAT continue to see that encoding if the device supports
// extended precision integers.
int[] encodingsPlusFloat = Arrays.copyOf(encodings, encodings.length + 1);
encodingsPlusFloat[encodings.length] = AudioFormat.ENCODING_PCM_FLOAT;
return encodingsPlusFloat;
}
return encodings;
} }
/** /**

View File

@@ -110,6 +110,24 @@ import java.util.Objects;
* <code>AudioTrack</code> as of API {@link android.os.Build.VERSION_CODES#LOLLIPOP} * <code>AudioTrack</code> as of API {@link android.os.Build.VERSION_CODES#LOLLIPOP}
* support <code>ENCODING_PCM_FLOAT</code>. * support <code>ENCODING_PCM_FLOAT</code>.
* </li> * </li>
* <li> {@link #ENCODING_PCM_24BIT_PACKED}: Introduced in
* API {@link android.os.Build.VERSION_CODES#S},
* this encoding specifies the audio sample is an
* extended precision 24 bit signed integer
* stored as a 3 Java bytes in a {@code ByteBuffer} or byte array in native endian
* (see {@link java.nio.ByteOrder#nativeOrder()}).
* Each sample has full range from [-8388608, 8388607],
* and can be interpreted as fixed point Q.23 data.
* </li>
* <li> {@link #ENCODING_PCM_32BIT}: Introduced in
* API {@link android.os.Build.VERSION_CODES#S},
* this encoding specifies the audio sample is an
* extended precision 32 bit signed integer
* stored as a 4 Java bytes in a {@code ByteBuffer} or byte array in native endian
* (see {@link java.nio.ByteOrder#nativeOrder()}).
* Each sample has full range from [-2147483648, 2147483647],
* and can be interpreted as fixed point Q.31 data.
* </li>
* </ul> * </ul>
* <p>For compressed audio, the encoding specifies the method of compression, * <p>For compressed audio, the encoding specifies the method of compression,
* for example {@link #ENCODING_AC3} and {@link #ENCODING_DTS}. The compressed * for example {@link #ENCODING_AC3} and {@link #ENCODING_DTS}. The compressed
@@ -285,6 +303,19 @@ public final class AudioFormat implements Parcelable {
/** Audio data format: OPUS compressed. */ /** Audio data format: OPUS compressed. */
public static final int ENCODING_OPUS = 20; public static final int ENCODING_OPUS = 20;
/** @hide
* We do not permit legacy short array reads or writes for encodings
* introduced after this threshold.
*/
public static final int ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD = ENCODING_OPUS;
/** Audio data format: PCM 24 bit per sample packed as 3 bytes.
* Not guaranteed to be supported by devices, may be emulated if not supported. */
public static final int ENCODING_PCM_24BIT_PACKED = 21;
/** Audio data format: PCM 32 bit per sample.
* Not guaranteed to be supported by devices, may be emulated if not supported. */
public static final int ENCODING_PCM_32BIT = 22;
/** @hide */ /** @hide */
public static String toLogFriendlyEncoding(int enc) { public static String toLogFriendlyEncoding(int enc) {
switch(enc) { switch(enc) {
@@ -328,6 +359,10 @@ public final class AudioFormat implements Parcelable {
return "ENCODING_DOLBY_MAT"; return "ENCODING_DOLBY_MAT";
case ENCODING_OPUS: case ENCODING_OPUS:
return "ENCODING_OPUS"; return "ENCODING_OPUS";
case ENCODING_PCM_24BIT_PACKED:
return "ENCODING_PCM_24BIT_PACKED";
case ENCODING_PCM_32BIT:
return "ENCODING_PCM_32BIT";
default : default :
return "invalid encoding " + enc; return "invalid encoding " + enc;
} }
@@ -517,17 +552,20 @@ public final class AudioFormat implements Parcelable {
public static int getBytesPerSample(int audioFormat) public static int getBytesPerSample(int audioFormat)
{ {
switch (audioFormat) { switch (audioFormat) {
case ENCODING_PCM_8BIT: case ENCODING_PCM_8BIT:
return 1; return 1;
case ENCODING_PCM_16BIT: case ENCODING_PCM_16BIT:
case ENCODING_IEC61937: case ENCODING_IEC61937:
case ENCODING_DEFAULT: case ENCODING_DEFAULT:
return 2; return 2;
case ENCODING_PCM_FLOAT: case ENCODING_PCM_24BIT_PACKED:
return 4; return 3;
case ENCODING_INVALID: case ENCODING_PCM_FLOAT:
default: case ENCODING_PCM_32BIT:
throw new IllegalArgumentException("Bad audio format " + audioFormat); return 4;
case ENCODING_INVALID:
default:
throw new IllegalArgumentException("Bad audio format " + audioFormat);
} }
} }
@@ -554,6 +592,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_E_AC3_JOC: case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT: case ENCODING_DOLBY_MAT:
case ENCODING_OPUS: case ENCODING_OPUS:
case ENCODING_PCM_24BIT_PACKED:
case ENCODING_PCM_32BIT:
return true; return true;
default: default:
return false; return false;
@@ -583,6 +623,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_E_AC3_JOC: case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT: case ENCODING_DOLBY_MAT:
case ENCODING_OPUS: case ENCODING_OPUS:
case ENCODING_PCM_24BIT_PACKED:
case ENCODING_PCM_32BIT:
return true; return true;
default: default:
return false; return false;
@@ -597,6 +639,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_PCM_16BIT: case ENCODING_PCM_16BIT:
case ENCODING_PCM_8BIT: case ENCODING_PCM_8BIT:
case ENCODING_PCM_FLOAT: case ENCODING_PCM_FLOAT:
case ENCODING_PCM_24BIT_PACKED:
case ENCODING_PCM_32BIT:
case ENCODING_DEFAULT: case ENCODING_DEFAULT:
return true; return true;
case ENCODING_AC3: case ENCODING_AC3:
@@ -630,6 +674,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_PCM_8BIT: case ENCODING_PCM_8BIT:
case ENCODING_PCM_FLOAT: case ENCODING_PCM_FLOAT:
case ENCODING_IEC61937: // same size as stereo PCM case ENCODING_IEC61937: // same size as stereo PCM
case ENCODING_PCM_24BIT_PACKED:
case ENCODING_PCM_32BIT:
case ENCODING_DEFAULT: case ENCODING_DEFAULT:
return true; return true;
case ENCODING_AC3: case ENCODING_AC3:
@@ -927,6 +973,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_E_AC3_JOC: case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT: case ENCODING_DOLBY_MAT:
case ENCODING_OPUS: case ENCODING_OPUS:
case ENCODING_PCM_24BIT_PACKED:
case ENCODING_PCM_32BIT:
mEncoding = encoding; mEncoding = encoding;
break; break;
case ENCODING_INVALID: case ENCODING_INVALID:
@@ -1147,7 +1195,9 @@ public final class AudioFormat implements Parcelable {
ENCODING_AC4, ENCODING_AC4,
ENCODING_E_AC3_JOC, ENCODING_E_AC3_JOC,
ENCODING_DOLBY_MAT, ENCODING_DOLBY_MAT,
ENCODING_OPUS } ENCODING_OPUS,
ENCODING_PCM_24BIT_PACKED,
ENCODING_PCM_32BIT }
) )
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface Encoding {} public @interface Encoding {}

View File

@@ -850,17 +850,21 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
//-------------- //--------------
// audio format // audio format
switch (audioFormat) { switch (audioFormat) {
case AudioFormat.ENCODING_DEFAULT: case AudioFormat.ENCODING_DEFAULT:
mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
break; break;
case AudioFormat.ENCODING_PCM_FLOAT: case AudioFormat.ENCODING_PCM_24BIT_PACKED:
case AudioFormat.ENCODING_PCM_16BIT: case AudioFormat.ENCODING_PCM_32BIT:
case AudioFormat.ENCODING_PCM_8BIT: case AudioFormat.ENCODING_PCM_FLOAT:
mAudioFormat = audioFormat; case AudioFormat.ENCODING_PCM_16BIT:
break; case AudioFormat.ENCODING_PCM_8BIT:
default: mAudioFormat = audioFormat;
throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat break;
+ ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT."); default:
throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat
+ ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,"
+ " ENCODING_PCM_24BIT_PACKED, ENCODING_PCM_32BIT,"
+ " or ENCODING_PCM_FLOAT.");
} }
} }
@@ -1267,6 +1271,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
*/ */
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@ReadMode int readMode) { @ReadMode int readMode) {
// Note: we allow reads of extended integers into a byte array.
if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
return ERROR_INVALID_OPERATION; return ERROR_INVALID_OPERATION;
} }
@@ -1339,7 +1344,10 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
*/ */
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
@ReadMode int readMode) { @ReadMode int readMode) {
if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { if (mState != STATE_INITIALIZED
|| mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT
// use ByteBuffer instead for later encodings
|| mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) {
return ERROR_INVALID_OPERATION; return ERROR_INVALID_OPERATION;
} }

View File

@@ -2892,7 +2892,7 @@ public class AudioTrack extends PlayerBase
*/ */
public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@WriteMode int writeMode) { @WriteMode int writeMode) {
// Note: we allow writes of extended integers and compressed formats from a byte array.
if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
return ERROR_INVALID_OPERATION; return ERROR_INVALID_OPERATION;
} }
@@ -3006,7 +3006,10 @@ public class AudioTrack extends PlayerBase
public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
@WriteMode int writeMode) { @WriteMode int writeMode) {
if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { if (mState == STATE_UNINITIALIZED
|| mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT
// use ByteBuffer or byte[] instead for later encodings
|| mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) {
return ERROR_INVALID_OPERATION; return ERROR_INVALID_OPERATION;
} }