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

Commit b5ebe300 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AudioTrack: support for offloaded playback"

parents db28e90b 980d38ff
Loading
Loading
Loading
Loading
+30 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,8 @@
#define ENCODING_AAC_HE_V2      12
#define ENCODING_AAC_HE_V2      12
#define ENCODING_IEC61937       13
#define ENCODING_IEC61937       13
#define ENCODING_DOLBY_TRUEHD   14
#define ENCODING_DOLBY_TRUEHD   14
#define ENCODING_AAC_ELD        15
#define ENCODING_AAC_XHE        16


#define ENCODING_INVALID    0
#define ENCODING_INVALID    0
#define ENCODING_DEFAULT    1
#define ENCODING_DEFAULT    1
@@ -71,6 +73,10 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
        return AUDIO_FORMAT_DOLBY_TRUEHD;
        return AUDIO_FORMAT_DOLBY_TRUEHD;
    case ENCODING_IEC61937:
    case ENCODING_IEC61937:
        return AUDIO_FORMAT_IEC61937;
        return AUDIO_FORMAT_IEC61937;
    case ENCODING_AAC_ELD:
        return AUDIO_FORMAT_AAC_ELD;
    case ENCODING_AAC_XHE:
        return AUDIO_FORMAT_AAC; // FIXME temporary value, needs addition of xHE-AAC
    case ENCODING_DEFAULT:
    case ENCODING_DEFAULT:
        return AUDIO_FORMAT_DEFAULT;
        return AUDIO_FORMAT_DEFAULT;
    default:
    default:
@@ -114,6 +120,11 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
        return ENCODING_IEC61937;
        return ENCODING_IEC61937;
    case AUDIO_FORMAT_DOLBY_TRUEHD:
    case AUDIO_FORMAT_DOLBY_TRUEHD:
        return ENCODING_DOLBY_TRUEHD;
        return ENCODING_DOLBY_TRUEHD;
    case AUDIO_FORMAT_AAC_ELD:
            return ENCODING_AAC_ELD;
    // FIXME needs addition of AUDIO_FORMAT_AAC_XHE
    //case AUDIO_FORMAT_AAC_XHE:
    //    return ENCODING_AAC_XHE;
    case AUDIO_FORMAT_DEFAULT:
    case AUDIO_FORMAT_DEFAULT:
        return ENCODING_DEFAULT;
        return ENCODING_DEFAULT;
    default:
    default:
@@ -121,6 +132,25 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
    }
    }
}
}


// 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)
{
    // 0 is the java android.media.AudioFormat.CHANNEL_INVALID value
    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)((uint32_t)channelPositionMask >> 2);
}

static inline audio_channel_mask_t outChannelMaskToNative(int channelMask)
static inline audio_channel_mask_t outChannelMaskToNative(int channelMask)
{
{
    switch (channelMask) {
    switch (channelMask) {
+19 −0
Original line number Original line Diff line number Diff line
@@ -1770,6 +1770,24 @@ android_media_AudioSystem_getStreamVolumeDB(JNIEnv *env, jobject thiz,
                                                  (audio_devices_t)device);
                                                  (audio_devices_t)device);
}
}


static jboolean
android_media_AudioSystem_isOffloadSupported(JNIEnv *env, jobject thiz,
        jint encoding, jint sampleRate, jint channelMask, jint channelIndexMask)
{
    audio_offload_info_t format = AUDIO_INFO_INITIALIZER;
    format.format = (audio_format_t) audioFormatToNative(encoding);
    format.sample_rate = (uint32_t) sampleRate;
    format.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
    format.stream_type = AUDIO_STREAM_MUSIC;
    format.has_video = false;
    format.is_streaming = false;
    // offload duration unknown at this point:
    // client side code cannot access "audio.offload.min.duration.secs" property to make a query
    // agnostic of duration, so using acceptable estimate of 2mn
    format.duration_us = 120 * 1000000;
    return AudioSystem::isOffloadSupported(format);
}

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


static const JNINativeMethod gMethods[] = {
static const JNINativeMethod gMethods[] = {
@@ -1823,6 +1841,7 @@ static const JNINativeMethod gMethods[] = {
                                    (void *)android_media_AudioSystem_registerRecordingCallback},
                                    (void *)android_media_AudioSystem_registerRecordingCallback},
    {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
    {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
    {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
    {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
    {"native_is_offload_supported", "(IIII)Z", (void *)android_media_AudioSystem_isOffloadSupported},
};
};




+37 −35
Original line number Original line Diff line number Diff line
@@ -73,6 +73,7 @@ struct audiotrack_callback_cookie {
    jobject     audioTrack_ref;
    jobject     audioTrack_ref;
    bool        busy;
    bool        busy;
    Condition   cond;
    Condition   cond;
    bool        isOffload;
};
};


// keep these values in sync with AudioTrack.java
// keep these values in sync with AudioTrack.java
@@ -90,6 +91,7 @@ class AudioTrackJniStorage {
    AudioTrackJniStorage() {
    AudioTrackJniStorage() {
        mCallbackData.audioTrack_class = 0;
        mCallbackData.audioTrack_class = 0;
        mCallbackData.audioTrack_ref = 0;
        mCallbackData.audioTrack_ref = 0;
        mCallbackData.isOffload = false;
    }
    }


    ~AudioTrackJniStorage() {
    ~AudioTrackJniStorage() {
@@ -132,7 +134,12 @@ static void audioCallback(int event, void* user, void *info) {
    }
    }


    switch (event) {
    switch (event) {
    case AudioTrack::EVENT_MARKER: {
    // Offload only events
    case AudioTrack::EVENT_STREAM_END:
    case AudioTrack::EVENT_MORE_DATA:
    // a.k.a. tear down
    case AudioTrack::EVENT_NEW_IAUDIOTRACK:
        if (callbackInfo->isOffload) {
            JNIEnv *env = AndroidRuntime::getJNIEnv();
            JNIEnv *env = AndroidRuntime::getJNIEnv();
            if (user != NULL && env != NULL) {
            if (user != NULL && env != NULL) {
                env->CallStaticVoidMethod(
                env->CallStaticVoidMethod(
@@ -146,6 +153,8 @@ static void audioCallback(int event, void* user, void *info) {
            }
            }
        } break;
        } break;


    // PCM and offload events
    case AudioTrack::EVENT_MARKER:
    case AudioTrack::EVENT_NEW_POS: {
    case AudioTrack::EVENT_NEW_POS: {
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        if (user != NULL && env != NULL) {
        if (user != NULL && env != NULL) {
@@ -198,30 +207,12 @@ sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audio
    return getAudioTrack(env, audioTrackObj);
    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
static jint
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
        jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
        jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
        jlong nativeAudioTrack) {
        jlong nativeAudioTrack, jboolean offload) {


    ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
    ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
        "nativeAudioTrack=0x%" PRIX64,
        "nativeAudioTrack=0x%" PRIX64,
@@ -322,8 +313,19 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
        lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
        lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
        // we use a weak reference so the AudioTrack object can be garbage collected.
        // we use a weak reference so the AudioTrack object can be garbage collected.
        lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
        lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
        lpJniStorage->mCallbackData.isOffload = offload;
        lpJniStorage->mCallbackData.busy = false;
        lpJniStorage->mCallbackData.busy = false;


        audio_offload_info_t offloadInfo;
        if (offload) {
            offloadInfo = AUDIO_INFO_INITIALIZER;
            offloadInfo.format = format;
            offloadInfo.sample_rate = sampleRateInHertz;
            offloadInfo.channel_mask = nativeChannelMask;
            offloadInfo.has_video = false;
            offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
        }

        // initialize the native AudioTrack object
        // initialize the native AudioTrack object
        status_t status = NO_ERROR;
        status_t status = NO_ERROR;
        switch (memoryMode) {
        switch (memoryMode) {
@@ -342,7 +344,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
                    true,// thread can call Java
                    true,// thread can call Java
                    sessionId,// audio session ID
                    sessionId,// audio session ID
                    AudioTrack::TRANSFER_SYNC,
                    AudioTrack::TRANSFER_SYNC,
                    NULL,                         // default offloadInfo
                    offload ? &offloadInfo : NULL,
                    -1, -1,                       // default uid, pid values
                    -1, -1,                       // default uid, pid values
                    paa);
                    paa);
            break;
            break;
@@ -1234,7 +1236,7 @@ static const JNINativeMethod gMethods[] = {
    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
    {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
    {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
    {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
    {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJ)I",
    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZ)I",
                                         (void *)android_media_AudioTrack_setup},
                                         (void *)android_media_AudioTrack_setup},
    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
    {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
    {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
+42 −11
Original line number Original line Diff line number Diff line
@@ -240,20 +240,25 @@ public final class AudioFormat implements Parcelable {
    public static final int ENCODING_DTS_HD = 8;
    public static final int ENCODING_DTS_HD = 8;
    /** Audio data format: MP3 compressed
    /** Audio data format: MP3 compressed
     * @hide
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
     * */
    public static final int ENCODING_MP3 = 9;
    public static final int ENCODING_MP3 = 9;
    /** Audio data format: AAC LC compressed
    /** Audio data format: AAC LC compressed
     * @hide
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
     * */
    public static final int ENCODING_AAC_LC = 10;
    public static final int ENCODING_AAC_LC = 10;
    /** Audio data format: AAC HE V1 compressed
    /** Audio data format: AAC HE V1 compressed
     * @hide
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
     * */
    public static final int ENCODING_AAC_HE_V1 = 11;
    public static final int ENCODING_AAC_HE_V1 = 11;
    /** Audio data format: AAC HE V2 compressed
    /** Audio data format: AAC HE V2 compressed
     * @hide
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
     * */
    public static final int ENCODING_AAC_HE_V2 = 12;
    public static final int ENCODING_AAC_HE_V2 = 12;

    /** Audio data format: compressed audio wrapped in PCM for HDMI
    /** Audio data format: compressed audio wrapped in PCM for HDMI
     * or S/PDIF passthrough.
     * or S/PDIF passthrough.
     * IEC61937 uses a stereo stream of 16-bit samples as the wrapper.
     * IEC61937 uses a stereo stream of 16-bit samples as the wrapper.
@@ -266,6 +271,16 @@ public final class AudioFormat implements Parcelable {
    /** Audio data format: DOLBY TRUEHD compressed
    /** Audio data format: DOLBY TRUEHD compressed
     **/
     **/
    public static final int ENCODING_DOLBY_TRUEHD = 14;
    public static final int ENCODING_DOLBY_TRUEHD = 14;
    /** Audio data format: AAC ELD compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_AAC_ELD = 15;
    /** Audio data format: AAC xHE compressed
     * @hide
     * TODO unhide and add to @Encoding (intentional white space   
     * */
    public static final int ENCODING_AAC_XHE = 16;


    /** @hide */
    /** @hide */
    public static String toLogFriendlyEncoding(int enc) {
    public static String toLogFriendlyEncoding(int enc) {
@@ -298,6 +313,10 @@ public final class AudioFormat implements Parcelable {
                return "ENCODING_IEC61937";
                return "ENCODING_IEC61937";
            case ENCODING_DOLBY_TRUEHD:
            case ENCODING_DOLBY_TRUEHD:
                return "ENCODING_DOLBY_TRUEHD";
                return "ENCODING_DOLBY_TRUEHD";
            case ENCODING_AAC_ELD:
                return "ENCODING_AAC_ELD";
            case ENCODING_AAC_XHE:
                return "ENCODING_AAC_XHE";
            default :
            default :
                return "invalid encoding " + enc;
                return "invalid encoding " + enc;
        }
        }
@@ -514,6 +533,8 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_AAC_HE_V2:
        case ENCODING_IEC61937:
        case ENCODING_IEC61937:
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return true;
            return true;
        default:
        default:
            return false;
            return false;
@@ -532,6 +553,13 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_DTS:
        case ENCODING_DTS:
        case ENCODING_DTS_HD:
        case ENCODING_DTS_HD:
        case ENCODING_IEC61937:
        case ENCODING_IEC61937:
            //TODO not true yet (intended white space     
        case ENCODING_MP3:
        case ENCODING_AAC_LC:
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return true;
            return true;
        default:
        default:
            return false;
            return false;
@@ -556,6 +584,8 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_AAC_HE_V2:
        case ENCODING_IEC61937: // wrapped in PCM but compressed
        case ENCODING_IEC61937: // wrapped in PCM but compressed
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return false;
            return false;
        case ENCODING_INVALID:
        case ENCODING_INVALID:
        default:
        default:
@@ -581,6 +611,8 @@ public final class AudioFormat implements Parcelable {
        case ENCODING_AAC_LC:
        case ENCODING_AAC_LC:
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V1:
        case ENCODING_AAC_HE_V2:
        case ENCODING_AAC_HE_V2:
        case ENCODING_AAC_ELD:
        case ENCODING_AAC_XHE:
            return false;
            return false;
        case ENCODING_INVALID:
        case ENCODING_INVALID:
        default:
        default:
@@ -794,14 +826,7 @@ public final class AudioFormat implements Parcelable {


        /**
        /**
         * Sets the data encoding format.
         * Sets the data encoding format.
         * @param encoding one of {@link AudioFormat#ENCODING_DEFAULT},
         * @param encoding the specified encoding or default.
         *     {@link AudioFormat#ENCODING_PCM_8BIT},
         *     {@link AudioFormat#ENCODING_PCM_16BIT},
         *     {@link AudioFormat#ENCODING_PCM_FLOAT},
         *     {@link AudioFormat#ENCODING_AC3},
         *     {@link AudioFormat#ENCODING_E_AC3}.
         *     {@link AudioFormat#ENCODING_DTS},
         *     {@link AudioFormat#ENCODING_DTS_HD}.
         * @return the same Builder instance.
         * @return the same Builder instance.
         * @throws java.lang.IllegalArgumentException
         * @throws java.lang.IllegalArgumentException
         */
         */
@@ -818,6 +843,12 @@ public final class AudioFormat implements Parcelable {
                case ENCODING_DTS:
                case ENCODING_DTS:
                case ENCODING_DTS_HD:
                case ENCODING_DTS_HD:
                case ENCODING_IEC61937:
                case ENCODING_IEC61937:
                case ENCODING_MP3:
                case ENCODING_AAC_LC:
                case ENCODING_AAC_HE_V1:
                case ENCODING_AAC_HE_V2:
                case ENCODING_AAC_ELD:
                case ENCODING_AAC_XHE:
                    mEncoding = encoding;
                    mEncoding = encoding;
                    break;
                    break;
                case ENCODING_INVALID:
                case ENCODING_INVALID:
@@ -1016,7 +1047,7 @@ public final class AudioFormat implements Parcelable {
    }
    }


    /** @hide */
    /** @hide */
    @IntDef({
    @IntDef(flag = false, prefix = "ENCODING", value = {
        ENCODING_DEFAULT,
        ENCODING_DEFAULT,
        ENCODING_PCM_8BIT,
        ENCODING_PCM_8BIT,
        ENCODING_PCM_16BIT,
        ENCODING_PCM_16BIT,
@@ -1025,8 +1056,8 @@ public final class AudioFormat implements Parcelable {
        ENCODING_E_AC3,
        ENCODING_E_AC3,
        ENCODING_DTS,
        ENCODING_DTS,
        ENCODING_DTS_HD,
        ENCODING_DTS_HD,
        ENCODING_IEC61937
        ENCODING_IEC61937 }
    })
    )
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Encoding {}
    public @interface Encoding {}


+15 −0
Original line number Original line Diff line number Diff line
@@ -1328,6 +1328,21 @@ public class AudioManager {
        }
        }
     }
     }


    //====================================================================
    // Offload query
    /**
     * @hide
     * TODO unhide (intentional white space to attract attention:    
     * Returns whether offloaded playback of an audio format is supported on the device.
     * Offloaded playback is where the decoding of an audio stream is not competing with other
     * software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
     * @param format the audio format (codec, sample rate, channels) being checked.
     * @return true if the given audio format can be offloaded.
     */
    public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
        return AudioSystem.isOffloadSupported(format);
    }

    //====================================================================
    //====================================================================
    // Bluetooth SCO control
    // Bluetooth SCO control
    /**
    /**
Loading