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

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

Merge "Move channel index computation to native AudioTrack JNI"

parents 20fd8475 30d79436
Loading
Loading
Loading
Loading
+25 −13
Original line number Diff line number Diff line
@@ -189,32 +189,44 @@ sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audio
    return getAudioTrack(env, audioTrackObj);
}

// This function converts Java channel masks to a native channel mask.
// validity should be checked with audio_is_output_channel().
static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
        jint channelPositionMask, jint channelIndexMask)
{
    if (channelIndexMask != 0) {  // channel index mask takes priority
        // To convert to a native channel mask, the Java channel index mask
        // requires adding the index representation.
        return audio_channel_mask_from_representation_and_bits(
                        AUDIO_CHANNEL_REPRESENTATION_INDEX,
                        channelIndexMask);
    }
    // To convert to a native channel mask, the Java channel position mask
    // requires a shift by 2 to skip the two deprecated channel
    // configurations "default" and "mono".
    return (audio_channel_mask_t)(channelPositionMask >> 2);
}

// ----------------------------------------------------------------------------
static jint
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
        jobject jaa,
        jint sampleRateInHertz, jint javaChannelMask,
        jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask,
        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {

    ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
        sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
    ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
        sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);

    if (jaa == 0) {
        ALOGE("Error creating AudioTrack: invalid audio attributes");
        return (jint) AUDIO_JAVA_ERROR;
    }

    // Java channel masks don't map directly to the native definition for positional
    // channel masks: it's a shift by 2 to skip the two deprecated channel
    // configurations "default" and "mono".
    // Invalid channel representations are caught by !audio_is_output_channel() below.
    audio_channel_mask_t nativeChannelMask =
            audio_channel_mask_get_representation(javaChannelMask)
                == AUDIO_CHANNEL_REPRESENTATION_POSITION
            ? javaChannelMask >> 2 : javaChannelMask;

    audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
            channelPositionMask, channelIndexMask);
    if (!audio_is_output_channel(nativeChannelMask)) {
        ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
        ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
        return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
    }

@@ -982,7 +994,7 @@ static JNINativeMethod gMethods[] = {
    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
    {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
    {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;IIIII[I)I",
    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I",
                                         (void *)android_media_AudioTrack_setup},
    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
    {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
+2 −49
Original line number Diff line number Diff line
@@ -491,7 +491,7 @@ public class AudioTrack
        session[0] = sessionId;
        // native initialization
        int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
                mSampleRate, mChannels, mAudioFormat,
                mSampleRate, mChannels, mChannelIndexMask, mAudioFormat,
                mNativeBufferSizeInBytes, mDataLoadMode, session);
        if (initResult != SUCCESS) {
            loge("Error code "+initResult+" when initializing AudioTrack.");
@@ -701,48 +701,6 @@ public class AudioTrack
            AudioFormat.CHANNEL_OUT_SIDE_LEFT |
            AudioFormat.CHANNEL_OUT_SIDE_RIGHT;

    // Java channel mask definitions below match those
    // in /system/core/include/system/audio.h in the JNI code of AudioTrack.

    // internal maximum size for bits parameter, not part of public API
    private static final int AUDIO_CHANNEL_BITS_LOG2 = 30;

    // log(2) of maximum number of representations, not part of public API
    private static final int AUDIO_CHANNEL_REPRESENTATION_LOG2 = 2;

    // used to create a channel index mask or channel position mask
    // with getChannelMaskFromRepresentationAndBits();
    private static final int CHANNEL_OUT_REPRESENTATION_POSITION = 0;
    private static final int CHANNEL_OUT_REPRESENTATION_INDEX = 2;

    /**
     * Return the channel mask from its representation and bits.
     *
     * This creates a channel mask for mChannels which combines a
     * representation field and a bits field.  This is for internal
     * communication to native code, not part of the public API.
     *
     * @param representation the type of channel mask,
     *   either CHANNEL_OUT_REPRESENTATION_POSITION
     *   or CHANNEL_OUT_REPRESENTATION_INDEX
     * @param bits is the channel bits specifying occupancy
     * @return the channel mask
     * @throws java.lang.IllegalArgumentException if representation is not recognized or
     *   the bits field is not acceptable for that representation
     */
    private static int getChannelMaskFromRepresentationAndBits(int representation, int bits) {
        switch (representation) {
        case CHANNEL_OUT_REPRESENTATION_POSITION:
        case CHANNEL_OUT_REPRESENTATION_INDEX:
            if ((bits & ~((1 << AUDIO_CHANNEL_BITS_LOG2) - 1)) != 0) {
                throw new IllegalArgumentException("invalid bits " + bits);
            }
            return representation << AUDIO_CHANNEL_BITS_LOG2 | bits;
        default:
            throw new IllegalArgumentException("invalid representation " + representation);
        }
    }

    // Convenience method for the constructor's parameter checks.
    // This is where constructor IllegalArgumentException-s are thrown
    // postconditions:
@@ -804,11 +762,6 @@ public class AudioTrack
            } else if (mChannelCount != channelIndexCount) {
                throw new IllegalArgumentException("Channel count must match");
            }

            // AudioTrack prefers to use the channel index configuration
            // over the channel position configuration if both are specified.
            mChannels = getChannelMaskFromRepresentationAndBits(
                    CHANNEL_OUT_REPRESENTATION_INDEX, mChannelIndexMask);
        }

        //--------------
@@ -2362,7 +2315,7 @@ public class AudioTrack
    //     AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC
    private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
            Object /*AudioAttributes*/ attributes,
            int sampleRate, int channelMask, int audioFormat,
            int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
            int buffSizeInBytes, int mode, int[] sessionId);

    private native final void native_finalize();