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

Commit 7ca2b895 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

Merge "AudioTrack write method with data in ByteBuffer"

parents 42a51ae8 7ca0452f
Loading
Loading
Loading
Loading
+41 −8
Original line number Diff line number Diff line
@@ -17,10 +17,12 @@

#define LOG_TAG "AudioTrack-JNI"

#include <jni.h>
#include <JNIHelp.h>
#include <JniConstants.h>
#include <android_runtime/AndroidRuntime.h>

#include "ScopedBytes.h"

#include <utils/Log.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
@@ -503,13 +505,13 @@ static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
}

// ----------------------------------------------------------------------------
jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte* data,
                  jint offsetInBytes, jint sizeInBytes) {
jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const jbyte* data,
                  jint offsetInBytes, jint sizeInBytes, bool blocking = true) {
    // give the data to the native AudioTrack object (the data starts at the offset)
    ssize_t written = 0;
    // regular write() or copy the data to the AudioTrack's shared memory?
    if (track->sharedBuffer() == 0) {
        written = track->write(data + offsetInBytes, sizeInBytes);
        written = track->write(data + offsetInBytes, sizeInBytes, blocking);
        // for compatibility with earlier behavior of write(), return 0 in this case
        if (written == (ssize_t) WOULD_BLOCK) {
            written = 0;
@@ -563,7 +565,8 @@ jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte* data,
static jint android_media_AudioTrack_write_byte(JNIEnv *env,  jobject thiz,
                                                  jbyteArray javaAudioData,
                                                  jint offsetInBytes, jint sizeInBytes,
                                                  jint javaAudioFormat) {
                                                  jint javaAudioFormat,
                                                  jboolean isWriteBlocking) {
    //ALOGV("android_media_AudioTrack_write_byte(offset=%d, sizeInBytes=%d) called",
    //    offsetInBytes, sizeInBytes);
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
@@ -590,7 +593,8 @@ static jint android_media_AudioTrack_write_byte(JNIEnv *env, jobject thiz,
        return 0;
    }

    jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
    jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes,
            isWriteBlocking == JNI_TRUE /* blocking */);

    env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);

@@ -600,6 +604,31 @@ static jint android_media_AudioTrack_write_byte(JNIEnv *env, jobject thiz,
}


// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env,  jobject thiz,
        jbyteArray javaBytes, jint byteOffset, jint offsetInBytes, jint sizeInBytes,
        jint javaAudioFormat, jboolean isWriteBlocking) {
    //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
    //    offsetInBytes, sizeInBytes);
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "Unable to retrieve AudioTrack pointer for write()");
        return 0;
    }

    ScopedBytesRO bytes(env, javaBytes);
    if (bytes.get() == NULL) {
        ALOGE("Error retrieving source of audio data to play, can't play");
        return AUDIOTRACK_ERROR_BAD_VALUE;
    }

    jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get() + byteOffset, offsetInBytes,
            sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);

    return written;
}

// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_write_short(JNIEnv *env,  jobject thiz,
                                                  jshortArray javaAudioData,
@@ -608,7 +637,8 @@ static jint android_media_AudioTrack_write_short(JNIEnv *env, jobject thiz,
    jint written = android_media_AudioTrack_write_byte(env, thiz,
                                                 (jbyteArray) javaAudioData,
                                                 offsetInShorts*2, sizeInShorts*2,
                                                 javaAudioFormat);
                                                 javaAudioFormat,
                                                 JNI_TRUE /*blocking write, legacy behavior*/);
    if (written > 0) {
        written /= 2;
    }
@@ -890,7 +920,10 @@ static JNINativeMethod gMethods[] = {
                                         (void *)android_media_AudioTrack_setup},
    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
    {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
    {"native_write_byte",    "([BIII)I", (void *)android_media_AudioTrack_write_byte},
    {"native_write_byte",    "([BIIIZ)I",(void *)android_media_AudioTrack_write_byte},
    {"native_write_native_bytes",
                             "(Ljava/lang/Object;IIIIZ)I",
                                         (void *)android_media_AudioTrack_write_native_bytes},
    {"native_write_short",   "([SIII)I", (void *)android_media_AudioTrack_write_short},
    {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
    {"native_get_native_frame_count",
+103 −2
Original line number Diff line number Diff line
@@ -16,8 +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.nio.NioUtils;

import android.annotation.IntDef;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -145,6 +150,28 @@ public class AudioTrack
    private final static String TAG = "android.media.AudioTrack";


    /** @hide */
    @IntDef({
        WRITE_BLOCKING,
        WRITE_NON_BLOCKING
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface WriteMode {}

    /**
     * @hide CANDIDATE FOR PUBLIC API
     * The write mode indicating the write operation will block until all data has been written,
     * to be used in {@link #write(ByteBuffer, int, int, int)}.
     */
    public final static int WRITE_BLOCKING = 0;
    /**
     * @hide CANDIDATE FOR PUBLIC API
     * The write mode indicating the write operation will return immediately after
     * queuing as much audio data for playback as possible without blocking, to be used in
     * {@link #write(ByteBuffer, int, int, int)}.
     */
    public final static int WRITE_NON_BLOCKING = 1;

    //--------------------------------------------------------------------------
    // Member variables
    //--------------------
@@ -1084,7 +1111,8 @@ public class AudioTrack
            return ERROR_BAD_VALUE;
        }

        int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
        int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat,
                true /*isBlocking*/);

        if ((mDataLoadMode == MODE_STATIC)
                && (mState == STATE_NO_STATIC_DATA)
@@ -1140,6 +1168,75 @@ public class AudioTrack
    }


    /**
     * @hide CANDIDATE FOR PUBLIC API
     * 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 its 0 offset, and the write
     * mode is ignored.
     * In streaming mode, the blocking behavior will depend on the write mode.
     * @param audioData the buffer that holds the data to play, starting at the position reported
     *     by <code>audioData.position()</code>.
     *     <BR>Note that this method will not update the position in this buffer, therefore when
     *     writing a loop to write all the data in the buffer, you should increment the
     *     <code>offsetInBytes</code> parameter at each pass by the amount that was previously
     *     written for this buffer.
     * @param offsetInBytes offset to read from in bytes (note this differs from
     *     <code>audioData.position()</code>).
     * @param sizeInBytes number of bytes to read (note this differs from
     *     <code>audioData.remaining()</code>).
     * @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 0 or a positive number of bytes that were written, or
     *     {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
     */
    public int write(ByteBuffer audioData, int offsetInBytes, int sizeInBytes,
            @WriteMode int writeMode) {

        if (mState == STATE_UNINITIALIZED) {
            Log.e(TAG, "AudioTrack.write() called in invalid state STATE_UNINITIALIZED");
            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) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
                || (offsetInBytes + sizeInBytes < 0)    // detect integer overflow
                || (offsetInBytes + sizeInBytes > audioData.remaining())) {
            Log.e(TAG, "AudioTrack.write() called with invalid size/offset values");
            return ERROR_BAD_VALUE;
        }

        int ret = 0;
        if (audioData.isDirect()) {
            ret = native_write_native_bytes(audioData,
                    audioData.position(),
                    offsetInBytes, sizeInBytes, mAudioFormat,
                    writeMode == WRITE_BLOCKING);
        } else {
            ret = native_write_byte(NioUtils.unsafeArray(audioData),
                    NioUtils.unsafeArrayOffset(audioData) + audioData.position() + offsetInBytes,
                    sizeInBytes, 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;
    }

    /**
     * Notifies the native resource to reuse the audio data already loaded in the native
     * layer, that is to rewind to start of buffer.
@@ -1339,11 +1436,15 @@ public class AudioTrack
    private native final void native_flush();

    private native final int native_write_byte(byte[] audioData,
                                               int offsetInBytes, int sizeInBytes, int format);
                                               int offsetInBytes, int sizeInBytes, int format,
                                               boolean isBlocking);

    private native final int native_write_short(short[] audioData,
                                                int offsetInShorts, int sizeInShorts, int format);

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

    private native final int native_reload_static();

    private native final int native_get_native_frame_count();