diff options
| -rw-r--r-- | core/api/current.txt | 2 | ||||
| -rw-r--r-- | core/jni/android_media_AudioFormat.h | 15 | ||||
| -rw-r--r-- | media/java/android/media/AudioDeviceInfo.java | 26 | ||||
| -rw-r--r-- | media/java/android/media/AudioFormat.java | 74 | ||||
| -rw-r--r-- | media/java/android/media/AudioRecord.java | 32 | ||||
| -rw-r--r-- | media/java/android/media/AudioTrack.java | 7 |
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; } |