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

Commit 30d79436 authored by Andy Hung's avatar Andy Hung
Browse files

Move channel index computation to native AudioTrack JNI

Change-Id: I047a9dcce13a38c11da165607d668dfb9d7fa335
parent 7fdf51b1
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);
        }

        //--------------
@@ -2361,7 +2314,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();