diff --git a/core/api/current.txt b/core/api/current.txt
index 0c637755bf5f0..dc19ad7989c74 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19386,6 +19386,8 @@ package android.media {
field public static final int ENCODING_MP3 = 9; // 0x9
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_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_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index b1b39f3e36ffe..5f2dcdf975b6c 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -39,6 +39,8 @@
#define ENCODING_E_AC3_JOC 18
#define ENCODING_DOLBY_MAT 19
#define ENCODING_OPUS 20
+#define ENCODING_PCM_24BIT_PACKED 21
+#define ENCODING_PCM_32BIT 22
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -92,6 +94,10 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_MAT;
case ENCODING_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:
return AUDIO_FORMAT_INVALID;
}
@@ -107,10 +113,15 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
case AUDIO_FORMAT_PCM_FLOAT:
return ENCODING_PCM_FLOAT;
- // map these to ENCODING_PCM_FLOAT
- case AUDIO_FORMAT_PCM_8_24_BIT:
+ // As of S, these extend integer precision formats now return more specific values
+ // than ENCODING_PCM_FLOAT.
case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return ENCODING_PCM_24BIT_PACKED;
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;
case AUDIO_FORMAT_AC3:
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index f79fc92477f77..270dffea429ee 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -23,6 +23,7 @@ import android.util.SparseIntArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
import java.util.Objects;
import java.util.TreeSet;
@@ -467,9 +468,32 @@ public final class AudioDeviceInfo {
* @see AudioFormat
*
* 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() {
- 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;
}
/**
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 090812e39c5fb..9373676a0204e 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -110,6 +110,24 @@ import java.util.Objects;
* AudioTrack as of API {@link android.os.Build.VERSION_CODES#LOLLIPOP}
* support ENCODING_PCM_FLOAT.
*
+ *
For compressed audio, the encoding specifies the method of compression, * 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. */ 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 */ public static String toLogFriendlyEncoding(int enc) { switch(enc) { @@ -328,6 +359,10 @@ public final class AudioFormat implements Parcelable { return "ENCODING_DOLBY_MAT"; case ENCODING_OPUS: return "ENCODING_OPUS"; + case ENCODING_PCM_24BIT_PACKED: + return "ENCODING_PCM_24BIT_PACKED"; + case ENCODING_PCM_32BIT: + return "ENCODING_PCM_32BIT"; default : return "invalid encoding " + enc; } @@ -561,17 +596,20 @@ public final class AudioFormat implements Parcelable { public static int getBytesPerSample(int audioFormat) { switch (audioFormat) { - case ENCODING_PCM_8BIT: - return 1; - case ENCODING_PCM_16BIT: - case ENCODING_IEC61937: - case ENCODING_DEFAULT: - return 2; - case ENCODING_PCM_FLOAT: - return 4; - case ENCODING_INVALID: - default: - throw new IllegalArgumentException("Bad audio format " + audioFormat); + case ENCODING_PCM_8BIT: + return 1; + case ENCODING_PCM_16BIT: + case ENCODING_IEC61937: + case ENCODING_DEFAULT: + return 2; + case ENCODING_PCM_24BIT_PACKED: + return 3; + case ENCODING_PCM_FLOAT: + case ENCODING_PCM_32BIT: + return 4; + case ENCODING_INVALID: + default: + throw new IllegalArgumentException("Bad audio format " + audioFormat); } } @@ -598,6 +636,8 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: return true; default: return false; @@ -627,6 +667,8 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: return true; default: return false; @@ -641,6 +683,8 @@ public final class AudioFormat implements Parcelable { case ENCODING_PCM_16BIT: case ENCODING_PCM_8BIT: case ENCODING_PCM_FLOAT: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: case ENCODING_DEFAULT: return true; case ENCODING_AC3: @@ -674,6 +718,8 @@ public final class AudioFormat implements Parcelable { case ENCODING_PCM_8BIT: case ENCODING_PCM_FLOAT: case ENCODING_IEC61937: // same size as stereo PCM + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: case ENCODING_DEFAULT: return true; case ENCODING_AC3: @@ -971,6 +1017,8 @@ public final class AudioFormat implements Parcelable { case ENCODING_E_AC3_JOC: case ENCODING_DOLBY_MAT: case ENCODING_OPUS: + case ENCODING_PCM_24BIT_PACKED: + case ENCODING_PCM_32BIT: mEncoding = encoding; break; case ENCODING_INVALID: @@ -1191,7 +1239,9 @@ public final class AudioFormat implements Parcelable { ENCODING_AC4, ENCODING_E_AC3_JOC, ENCODING_DOLBY_MAT, - ENCODING_OPUS } + ENCODING_OPUS, + ENCODING_PCM_24BIT_PACKED, + ENCODING_PCM_32BIT } ) @Retention(RetentionPolicy.SOURCE) public @interface Encoding {} diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index d670f073fe8bb..52233b65ce6d0 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -845,17 +845,21 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, //-------------- // audio format switch (audioFormat) { - case AudioFormat.ENCODING_DEFAULT: - mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; - break; - case AudioFormat.ENCODING_PCM_FLOAT: - case AudioFormat.ENCODING_PCM_16BIT: - case AudioFormat.ENCODING_PCM_8BIT: - mAudioFormat = audioFormat; - break; - default: - throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat - + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT."); + case AudioFormat.ENCODING_DEFAULT: + mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; + break; + case AudioFormat.ENCODING_PCM_24BIT_PACKED: + case AudioFormat.ENCODING_PCM_32BIT: + case AudioFormat.ENCODING_PCM_FLOAT: + case AudioFormat.ENCODING_PCM_16BIT: + case AudioFormat.ENCODING_PCM_8BIT: + mAudioFormat = audioFormat; + break; + 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."); } } @@ -1262,6 +1266,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, */ public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode) { + // Note: we allow reads of extended integers into a byte array. if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { return ERROR_INVALID_OPERATION; } @@ -1334,7 +1339,10 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, */ public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, @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; } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 67880a589b430..7c91f52affa6e 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -2992,7 +2992,7 @@ public class AudioTrack extends PlayerBase */ public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, @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) { return ERROR_INVALID_OPERATION; } @@ -3106,7 +3106,10 @@ public class AudioTrack extends PlayerBase public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, @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; }