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

Commit eea64a92 authored by Glenn Kasten's avatar Glenn Kasten Committed by Android (Google) Code Review
Browse files

Merge "Add hidden support for ENCODING_PCM_FLOAT to AudioTrack"

parents 6e058419 54955e33
Loading
Loading
Loading
Loading
+45 −3
Original line number Original line Diff line number Diff line
@@ -526,12 +526,15 @@ jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const jbyte* da
        switch (format) {
        switch (format) {


        default:
        default:
            // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT
            // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT,
            // and AUDIO_FORMAT_PCM_8_BIT, due to the limited set of values for audioFormat.
            // AUDIO_FORMAT_PCM_8_BIT, and AUDIO_FORMAT_PCM_FLOAT,
            // due to the limited set of values for audioFormat.
            // The next section of the switch will probably work for more formats, but it has only
            // The next section of the switch will probably work for more formats, but it has only
            // been tested for AUDIO_FORMAT_PCM_16_BIT, so that's why the "default" case fails.
            // been tested for AUDIO_FORMAT_PCM_16_BIT and AUDIO_FORMAT_PCM_FLOAT,
            // so that's why the "default" case fails.
            break;
            break;


        case AUDIO_FORMAT_PCM_FLOAT:
        case AUDIO_FORMAT_PCM_16_BIT: {
        case AUDIO_FORMAT_PCM_16_BIT: {
            // writing to shared memory, check for capacity
            // writing to shared memory, check for capacity
            if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
            if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
@@ -678,6 +681,44 @@ static jint android_media_AudioTrack_write_short(JNIEnv *env, jobject thiz,
}
}




// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_write_float(JNIEnv *env,  jobject thiz,
                                                  jfloatArray javaAudioData,
                                                  jint offsetInFloats, jint sizeInFloats,
                                                  jint javaAudioFormat,
                                                  jboolean isWriteBlocking) {

    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
            "Unable to retrieve AudioTrack pointer for write()");
        return 0;
    }

    jfloat* cAudioData = NULL;
    if (javaAudioData) {
        cAudioData = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
        if (cAudioData == NULL) {
            ALOGE("Error retrieving source of audio data to play, can't play");
            return 0; // out of memory or no data to load
        }
    } else {
        ALOGE("NULL java array of audio data to play, can't play");
        return 0;
    }
    jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
                                offsetInFloats * sizeof(float), sizeInFloats * sizeof(float),
                                isWriteBlocking == JNI_TRUE /* blocking */);
    env->ReleaseFloatArrayElements(javaAudioData, cAudioData, 0);

    if (written > 0) {
        written /= sizeof(float);
    }

    return written;
}


// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env,  jobject thiz) {
static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env,  jobject thiz) {
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
@@ -963,6 +1004,7 @@ static JNINativeMethod gMethods[] = {
                             "(Ljava/lang/Object;IIIZ)I",
                             "(Ljava/lang/Object;IIIZ)I",
                                         (void *)android_media_AudioTrack_write_native_bytes},
                                         (void *)android_media_AudioTrack_write_native_bytes},
    {"native_write_short",   "([SIII)I", (void *)android_media_AudioTrack_write_short},
    {"native_write_short",   "([SIII)I", (void *)android_media_AudioTrack_write_short},
    {"native_write_float",   "([FIIIZ)I",(void *)android_media_AudioTrack_write_float},
    {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
    {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
    {"native_get_native_frame_count",
    {"native_get_native_frame_count",
                             "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
                             "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
+98 −6
Original line number Original line Diff line number Diff line
@@ -72,6 +72,7 @@ import com.android.internal.app.IAppOpsService;
 *
 *
 * AudioTrack is not final and thus permits subclasses, but such use is not recommended.
 * AudioTrack is not final and thus permits subclasses, but such use is not recommended.
 */
 */
// add {@link #write(float[], int, int)} when @hide removed
public class AudioTrack
public class AudioTrack
{
{
    //---------------------------------------------------------
    //---------------------------------------------------------
@@ -245,6 +246,7 @@ public class AudioTrack
     * @see AudioFormat#ENCODING_PCM_8BIT
     * @see AudioFormat#ENCODING_PCM_8BIT
     * @see AudioFormat#ENCODING_PCM_16BIT
     * @see AudioFormat#ENCODING_PCM_16BIT
     */
     */
    // add @see AudioFormat#ENCODING_PCM_FLOAT when @hide removed
    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
    /**
    /**
     * Audio session ID
     * Audio session ID
@@ -300,6 +302,7 @@ public class AudioTrack
     * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
     * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
     * @throws java.lang.IllegalArgumentException
     * @throws java.lang.IllegalArgumentException
     */
     */
    // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed
    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode)
            int bufferSizeInBytes, int mode)
    throws IllegalArgumentException {
    throws IllegalArgumentException {
@@ -341,6 +344,7 @@ public class AudioTrack
     * @param sessionId Id of audio session the AudioTrack must be attached to
     * @param sessionId Id of audio session the AudioTrack must be attached to
     * @throws java.lang.IllegalArgumentException
     * @throws java.lang.IllegalArgumentException
     */
     */
    // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed
    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode, int sessionId)
            int bufferSizeInBytes, int mode, int sessionId)
    throws IllegalArgumentException {
    throws IllegalArgumentException {
@@ -459,11 +463,14 @@ public class AudioTrack
            break;
            break;
        case AudioFormat.ENCODING_PCM_16BIT:
        case AudioFormat.ENCODING_PCM_16BIT:
        case AudioFormat.ENCODING_PCM_8BIT:
        case AudioFormat.ENCODING_PCM_8BIT:
        case AudioFormat.ENCODING_PCM_FLOAT:
            mAudioFormat = audioFormat;
            mAudioFormat = audioFormat;
            break;
            break;
        default:
        default:
            throw new IllegalArgumentException("Unsupported sample encoding."
            throw new IllegalArgumentException("Unsupported sample encoding."
                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT"
             // + " or ENCODING_PCM_FLOAT" when @hide removed
                + ".");
        }
        }


        //--------------
        //--------------
@@ -728,6 +735,7 @@ public class AudioTrack
     *   or {@link #ERROR} if unable to query for output properties,
     *   or {@link #ERROR} if unable to query for output properties,
     *   or the minimum buffer size expressed in bytes.
     *   or the minimum buffer size expressed in bytes.
     */
     */
    // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed
    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
        int channelCount = 0;
        int channelCount = 0;
        switch(channelConfig) {
        switch(channelConfig) {
@@ -750,7 +758,8 @@ public class AudioTrack
        }
        }


        if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
        if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)
            && (audioFormat != AudioFormat.ENCODING_PCM_FLOAT)) {
            loge("getMinBufferSize(): Invalid audio format.");
            loge("getMinBufferSize(): Invalid audio format.");
            return ERROR_BAD_VALUE;
            return ERROR_BAD_VALUE;
        }
        }
@@ -1150,7 +1159,7 @@ public class AudioTrack


    public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {
    public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {


        if (mState == STATE_UNINITIALIZED) {
        if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
            return ERROR_INVALID_OPERATION;
            return ERROR_INVALID_OPERATION;
        }
        }


@@ -1194,7 +1203,7 @@ public class AudioTrack


    public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
    public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {


        if (mState == STATE_UNINITIALIZED) {
        if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
            return ERROR_INVALID_OPERATION;
            return ERROR_INVALID_OPERATION;
        }
        }


@@ -1217,6 +1226,80 @@ public class AudioTrack
    }
    }




    /**
     * Writes the audio data to the audio sink for playback (streaming mode),
     * or copies audio data for later playback (static buffer mode).
     * In static buffer mode, copies the data to the buffer starting at offset 0,
     * and the write mode is ignored.
     * In streaming mode, the blocking behavior will depend on the write mode.
     * <p>
     * Note that the actual playback of this data might occur after this function
     * returns. This function is thread safe with respect to {@link #stop} calls,
     * in which case all of the specified data might not be written to the audio sink.
     * <p>
     * @param audioData the array that holds the data to play.
     *     The implementation does not clip for sample values within the nominal range
     *     [-1.0f, 1.0f], provided that all gains in the audio pipeline are
     *     less than or equal to unity (1.0f), and in the absence of post-processing effects
     *     that could add energy, such as reverb.  For the convenience of applications
     *     that compute samples using filters with non-unity gain,
     *     sample values +3 dB beyond the nominal range are permitted.
     *     However such values may eventually be limited or clipped, depending on various gains
     *     and later processing in the audio path.  Therefore applications are encouraged
     *     to provide samples values within the nominal range.
     * @param offsetInFloats the offset, expressed as a number of floats,
     *     in audioData where the data to play starts.
     * @param sizeInFloats the number of floats to read in audioData after the offset.
     * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
     *     effect in static mode.
     *     <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
     *         to the audio sink.
     *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
     *     queuing as much audio data for playback as possible without blocking.
     * @return the number of floats that were written, 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.
     * @hide candidate for public API
     */
    public int write(float[] audioData, int offsetInFloats, int sizeInFloats,
            @WriteMode int writeMode) {

        if (mState == STATE_UNINITIALIZED) {
            Log.e(TAG, "AudioTrack.write() called in invalid state STATE_UNINITIALIZED");
            return ERROR_INVALID_OPERATION;
        }

        if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
            Log.e(TAG, "AudioTrack.write(float[] ...) requires format ENCODING_PCM_FLOAT");
            return ERROR_INVALID_OPERATION;
        }

        if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
            Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
            return ERROR_BAD_VALUE;
        }

        if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0)
                || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
                || (offsetInFloats + sizeInFloats > audioData.length)) {
            Log.e(TAG, "AudioTrack.write() called with invalid array, offset, or size");
            return ERROR_BAD_VALUE;
        }

        int ret = native_write_float(audioData, offsetInFloats, sizeInFloats, mAudioFormat,
                writeMode == WRITE_BLOCKING);

        if ((mDataLoadMode == MODE_STATIC)
                && (mState == STATE_NO_STATIC_DATA)
                && (ret > 0)) {
            // benign race with respect to other APIs that read mState
            mState = STATE_INITIALIZED;
        }

        return ret;
    }


    /**
    /**
     * Writes the audio data to the audio sink for playback (streaming mode),
     * Writes the audio data to the audio sink for playback (streaming mode),
     * or copies audio data for later playback (static buffer mode).
     * or copies audio data for later playback (static buffer mode).
@@ -1247,6 +1330,11 @@ public class AudioTrack
            return ERROR_INVALID_OPERATION;
            return ERROR_INVALID_OPERATION;
        }
        }


        if (mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
            Log.e(TAG, "AudioTrack.write(ByteBuffer ...) not yet supported for ENCODING_PCM_FLOAT");
            return ERROR_INVALID_OPERATION;
        }

        if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
        if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
            Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
            Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
            return ERROR_BAD_VALUE;
            return ERROR_BAD_VALUE;
@@ -1487,6 +1575,10 @@ public class AudioTrack
    private native final int native_write_short(short[] audioData,
    private native final int native_write_short(short[] audioData,
                                                int offsetInShorts, int sizeInShorts, int format);
                                                int offsetInShorts, int sizeInShorts, int format);


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

    private native final int native_write_native_bytes(Object audioData,
    private native final int native_write_native_bytes(Object audioData,
            int positionInBytes, int sizeInBytes, int format, boolean blocking);
            int positionInBytes, int sizeInBytes, int format, boolean blocking);