Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ef1305a authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Add floating point AudioRecord read"

parents 0e67d0a1 58b0f3f3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -14669,6 +14669,7 @@ package android.media {
    method public int getState();
    method public int read(byte[], int, int);
    method public int read(short[], int, int);
    method public int read(float[], int, int, int);
    method public int read(java.nio.ByteBuffer, int);
    method public void release();
    method public int setNotificationMarkerPosition(int);
@@ -14681,6 +14682,8 @@ package android.media {
    field public static final int ERROR = -1; // 0xffffffff
    field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
    field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
    field public static final int READ_BLOCKING = 0; // 0x0
    field public static final int READ_NON_BLOCKING = 1; // 0x1
    field public static final int RECORDSTATE_RECORDING = 3; // 0x3
    field public static final int RECORDSTATE_STOPPED = 1; // 0x1
    field public static final int STATE_INITIALIZED = 1; // 0x1
+3 −0
Original line number Diff line number Diff line
@@ -15876,6 +15876,7 @@ package android.media {
    method public int getState();
    method public int read(byte[], int, int);
    method public int read(short[], int, int);
    method public int read(float[], int, int, int);
    method public int read(java.nio.ByteBuffer, int);
    method public void release();
    method public int setNotificationMarkerPosition(int);
@@ -15888,6 +15889,8 @@ package android.media {
    field public static final int ERROR = -1; // 0xffffffff
    field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
    field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
    field public static final int READ_BLOCKING = 0; // 0x0
    field public static final int READ_NON_BLOCKING = 1; // 0x1
    field public static final int RECORDSTATE_RECORDING = 3; // 0x3
    field public static final int RECORDSTATE_STOPPED = 1; // 0x1
    field public static final int STATE_INITIALIZED = 1; // 0x1
+53 −0
Original line number Diff line number Diff line
@@ -440,6 +440,57 @@ static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thi
    return (jint) readSize;
}

// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_readInFloatArray(JNIEnv *env,  jobject thiz,
                                                        jfloatArray javaAudioData,
                                                        jint offsetInFloats, jint sizeInFloats,
                                                        jboolean isReadBlocking) {
    // get the audio recorder from which we'll read new audio samples
    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    if (lpRecorder == NULL) {
        ALOGE("Unable to retrieve AudioRecord object");
        return (jint)AUDIO_JAVA_INVALID_OPERATION;
    }

    if (javaAudioData == NULL) {
         ALOGE("Invalid Java array to store recorded audio");
         return (jint)AUDIO_JAVA_BAD_VALUE;
     }

    // get the pointer to where we'll record the audio
    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
    // a way that it becomes much more efficient. When doing so, we will have to prevent the
    // AudioSystem callback to be called while in critical section (in case of media server
    // process crash for instance)
    jfloat *recordBuff = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
    if (recordBuff == NULL) {
        ALOGE("Error retrieving destination for recorded audio data");
        return (jint)AUDIO_JAVA_BAD_VALUE;
    }

    // read the new audio data from the native AudioRecord object
    const size_t sizeInBytes = sizeInFloats * sizeof(float);
    ssize_t readSize = lpRecorder->read(recordBuff + offsetInFloats, sizeInBytes);

    env->ReleaseFloatArrayElements(javaAudioData, recordBuff, 0);

    if (readSize < 0) {
        ALOGE_IF(readSize != WOULD_BLOCK, "Error %zd during AudioRecord native read", readSize);
        switch (readSize) {
        case WOULD_BLOCK:
            return (jint)0;
        case BAD_VALUE:
            return (jint)AUDIO_JAVA_BAD_VALUE;
        default:
            // may be possible for other errors such as
            // NO_INIT to happen if restoreRecord_l fails.
        case INVALID_OPERATION:
            return (jint)AUDIO_JAVA_INVALID_OPERATION;
        }
    }
    return (jint)(readSize / sizeof(float));
}

// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env,  jobject thiz,
                                                  jobject jBuffer, jint sizeInBytes) {
@@ -574,6 +625,8 @@ static JNINativeMethod gMethods[] = {
                             "([BII)I", (void *)android_media_AudioRecord_readInByteArray},
    {"native_read_in_short_array",
                             "([SII)I", (void *)android_media_AudioRecord_readInShortArray},
    {"native_read_in_float_array",
                             "([FIIZ)I", (void *)android_media_AudioRecord_readInFloatArray},
    {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I",
                                       (void *)android_media_AudioRecord_readInDirectBuffer},
    {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
+83 −19
Original line number Diff line number Diff line
@@ -16,10 +16,13 @@

package android.media;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Iterator;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Binder;
@@ -109,6 +112,26 @@ public class AudioRecord
    /** @hide */
    public final static String SUBMIX_FIXED_VOLUME = "fixedVolume";

    /** @hide */
    @IntDef({
        READ_BLOCKING,
        READ_NON_BLOCKING
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ReadMode {}

    /**
     * The read mode indicating the read operation will block until all data
     * requested has been read.
     */
    public final static int READ_BLOCKING = 0;

    /**
     * The read mode indicating the read operation will return immediately after
     * reading as much audio data as possible without blocking.
     */
    public final static int READ_NON_BLOCKING = 1;

    //---------------------------------------------------------
    // Used exclusively by native code
    //--------------------
@@ -144,6 +167,7 @@ public class AudioRecord
     * The encoding of the audio samples.
     * @see AudioFormat#ENCODING_PCM_8BIT
     * @see AudioFormat#ENCODING_PCM_16BIT
     * @see AudioFormat#ENCODING_PCM_FLOAT
     */
    private int mAudioFormat;
    /**
@@ -212,9 +236,9 @@ public class AudioRecord
     *   See {@link AudioFormat#CHANNEL_IN_MONO} and
     *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
     *   to work on all devices.
     * @param audioFormat the format in which the audio data is represented.
     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
     *   {@link AudioFormat#ENCODING_PCM_8BIT}
     * @param audioFormat the format in which the audio data is to be returned.
     *   See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
     * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
     *   to during the recording. New audio data can be read from this buffer in smaller chunks
     *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
@@ -559,13 +583,14 @@ public class AudioRecord
        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."
                    + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
                    + " Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT.");
        }
    }

@@ -573,7 +598,8 @@ public class AudioRecord
    // Convenience method for the contructor's audio buffer size check.
    // preconditions:
    //    mChannelCount is valid
    //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT
    //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT,
    //                 or AudioFormat.ENCODING_PCM_FLOAT
    // postcondition:
    //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
    private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException {
@@ -632,8 +658,8 @@ public class AudioRecord
    }

    /**
     * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
     * and {@link AudioFormat#ENCODING_PCM_8BIT}.
     * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_8BIT},
     * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}.
     */
    public int getAudioFormat() {
        return mAudioFormat;
@@ -732,12 +758,6 @@ public class AudioRecord
            return ERROR_BAD_VALUE;
        }

        // PCM_8BIT is not supported at the moment
        if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
            loge("getMinBufferSize(): Invalid audio format.");
            return ERROR_BAD_VALUE;
        }

        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
        if (size == 0) {
            return ERROR_BAD_VALUE;
@@ -841,11 +861,13 @@ public class AudioRecord
    // Audio data supply
    //--------------------
    /**
     * Reads audio data from the audio hardware for recording into a buffer.
     * Reads audio data from the audio hardware for recording into a byte array.
     * The format specified in the AudioRecord constructor should be
     * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
     * @param audioData the array to which the recorded audio data is written.
     * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
     * @param sizeInBytes the number of requested bytes.
     * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
     *    the parameters don't resolve to valid data and indexes.
     *    The number of bytes will not exceed sizeInBytes.
@@ -866,11 +888,13 @@ public class AudioRecord


    /**
     * Reads audio data from the audio hardware for recording into a buffer.
     * Reads audio data from the audio hardware for recording into a short array.
     * The format specified in the AudioRecord constructor should be
     * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
     * @param audioData the array to which the recorded audio data is written.
     * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
     * @param sizeInShorts the number of requested shorts.
     * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION}
     * @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
     *    the parameters don't resolve to valid data and indexes.
     *    The number of shorts will not exceed sizeInShorts.
@@ -889,18 +913,55 @@ public class AudioRecord
        return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
    }

    /**
     * Reads audio data from the audio hardware for recording into a float array.
     * The format specified in the AudioRecord constructor should be
     * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
     * @param audioData the array to which the recorded audio data is written.
     * @param offsetInFloats index in audioData from which the data is written.
     * @param sizeInFloats the number of requested floats.
     * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
     *     <BR>With {@link #READ_BLOCKING}, the read will block until all the requested data
     *     is read.
     *     <BR>With {@link #READ_NON_BLOCKING}, the read will return immediately after
     *     reading as much audio data as possible without blocking.
     * @return the number of floats that were read or {@link #ERROR_INVALID_OPERATION}
     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
     *    the parameters don't resolve to valid data and indexes.
     *    The number of floats will not exceed sizeInFloats.
     */
    public int read(float[] audioData, int offsetInFloats, int sizeInFloats,
            @ReadMode int readMode) {
        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }

        if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0)
                || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
                || (offsetInFloats + sizeInFloats > audioData.length)) {
            return ERROR_BAD_VALUE;
        }

        return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats,
                readMode == READ_BLOCKING);
    }

    /**
     * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
     * is not a direct buffer, this method will always return 0.
     * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
     * unchanged after a call to this method.
     * The representation of the data in the buffer will depend on the format specified in
     * the AudioRecord constructor, and will be native endian.
     * @param audioBuffer the direct buffer to which the recorded audio data is written.
     * @param sizeInBytes the number of requested bytes.
     * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
     * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
     *    that the number of bytes requested be a multiple of the frame size (sample size in
     *    bytes multiplied by the channel count).
     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
     *    the parameters don't resolve to valid data and indexes.
     *    The number of bytes will not exceed sizeInBytes.
     *    The number of bytes read will truncated to be a multiple of the frame size.
     */
    public int read(ByteBuffer audioBuffer, int sizeInBytes) {
        if (mState != STATE_INITIALIZED) {
@@ -1101,6 +1162,9 @@ public class AudioRecord
    private native final int native_read_in_short_array(short[] audioData,
            int offsetInShorts, int sizeInShorts);

    private native final int native_read_in_float_array(float[] audioData,
            int offsetInFloats, int sizeInFloats, boolean isBlocking);

    private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);

    private native final int native_set_marker_pos(int marker);