summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt2
-rw-r--r--core/jni/android_media_AudioFormat.h15
-rw-r--r--media/java/android/media/AudioDeviceInfo.java26
-rw-r--r--media/java/android/media/AudioFormat.java74
-rw-r--r--media/java/android/media/AudioRecord.java32
-rw-r--r--media/java/android/media/AudioTrack.java7
6 files changed, 127 insertions, 29 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 5a2b8bdd3c0a..cc29018000a7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19383,6 +19383,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 b1b39f3e36ff..5f2dcdf975b6 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 f79fc92477f7..270dffea429e 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 1d06e2837841..172e9d8d0e55 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -110,6 +110,24 @@ import java.util.Objects;
* <code>AudioTrack</code> as of API {@link android.os.Build.VERSION_CODES#LOLLIPOP}
* support <code>ENCODING_PCM_FLOAT</code>.
* </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>
* <p>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;
}
@@ -517,17 +552,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);
}
}
@@ -554,6 +592,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;
@@ -583,6 +623,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;
@@ -597,6 +639,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:
@@ -630,6 +674,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:
@@ -927,6 +973,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:
@@ -1147,7 +1195,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 d670f073fe8b..52233b65ce6d 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 b265ebfc02a0..81fadddea902 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2962,7 +2962,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;
}
@@ -3076,7 +3076,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;
}